oneslash-design-system 1.4.0 → 1.6.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/dist/components/alert.jsx +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/button.jsx +6 -4
- package/dist/components/icon.d.ts +1 -1
- package/dist/components/icon.jsx +1 -0
- package/dist/components/iconButton.d.ts +1 -1
- package/dist/components/iconButton.jsx +9 -10
- package/dist/components/loadingScreen.d.ts +1 -1
- package/dist/components/loadingScreen.jsx +1 -0
- package/dist/components/menuItem.d.ts +1 -1
- package/dist/components/menuItem.jsx +7 -5
- package/dist/components/tab.d.ts +2 -1
- package/dist/components/tab.jsx +22 -11
- package/dist/components/tabsContainer.d.ts +1 -0
- package/dist/components/tabsContainer.jsx +68 -4
- package/dist/components/tag.d.ts +1 -1
- package/dist/components/tag.jsx +6 -2
- package/dist/components/textField.d.ts +1 -1
- package/dist/components/textField.jsx +1 -0
- package/dist/components/textarea.d.ts +1 -1
- package/dist/components/textarea.jsx +1 -0
- package/dist/components/tooltip.jsx +25 -11
- package/dist/designTokens.js +5 -5
- package/dist/output.css +144 -31
- package/dist/stories/Button.stories.jsx +2 -1
- package/dist/stories/Icon.stories.jsx +1 -1
- package/dist/stories/IconButton.stories.jsx +2 -1
- package/dist/stories/MenuItem.stories.jsx +1 -1
- package/dist/stories/TabsContainer.stories.d.ts +2 -0
- package/dist/stories/TabsContainer.stories.jsx +14 -2
- package/dist/stories/Tag.stories.jsx +1 -1
- package/dist/stories/TextField.stories.jsx +1 -1
- package/dist/stories/Textarea.stories.jsx +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -2
|
@@ -50,7 +50,7 @@ export default function Alert(_a) {
|
|
|
50
50
|
if (!shouldRender)
|
|
51
51
|
return null;
|
|
52
52
|
var bgClasses = (_b = bgClassMap[type]) !== null && _b !== void 0 ? _b : bgClassMap.default;
|
|
53
|
-
var alertContent = (<div className={"flex items-start justify-between w-full p-2 rounded-[8px] transition-opacity duration-
|
|
53
|
+
var alertContent = (<div className={"flex items-start justify-between w-full p-2 rounded-[8px] transition-[opacity,transform] duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:transition-none ".concat(bgClasses, " ").concat(isVisible ? 'opacity-100 translate-y-0 scale-100' : variant === 'toast' ? 'opacity-0 -translate-y-3 scale-95' : 'opacity-0', " ").concat(variant === 'toast' ? 'max-w-md pointer-events-auto' : '')}>
|
|
54
54
|
<div className="flex items-start gap-2 text-light-text-primary dark:text-dark-text-primary">
|
|
55
55
|
<div className="flex flex-col text-left">
|
|
56
56
|
<span className="text-body2">{message}</span>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
interface ButtonProps {
|
|
3
|
-
size: 'small' | 'medium' | 'large';
|
|
3
|
+
size: 'tiny' | 'small' | 'medium' | 'large';
|
|
4
4
|
type: 'primary' | 'secondary' | 'tertiary' | 'textOnly';
|
|
5
5
|
color?: 'default' | 'danger';
|
|
6
6
|
state: 'enabled' | 'hovered' | 'focused' | 'disabled' | 'selected';
|
|
@@ -94,11 +94,13 @@ export default function Button(_a) {
|
|
|
94
94
|
large: 'text-body1 p-2',
|
|
95
95
|
medium: 'text-body1 p-1',
|
|
96
96
|
small: 'text-body2 p-1',
|
|
97
|
+
tiny: 'text-caption px-1 py-px',
|
|
97
98
|
}[size];
|
|
98
99
|
var sizeIcon = {
|
|
99
100
|
large: 'w-6 h-6',
|
|
100
101
|
medium: 'w-5 h-5',
|
|
101
102
|
small: 'w-4 h-4',
|
|
103
|
+
tiny: 'w-3.5 h-3.5',
|
|
102
104
|
}[size];
|
|
103
105
|
var baseTypeClasses = {
|
|
104
106
|
default: {
|
|
@@ -109,7 +111,7 @@ export default function Button(_a) {
|
|
|
109
111
|
},
|
|
110
112
|
danger: {
|
|
111
113
|
primary: 'bg-light-error-main dark:bg-dark-error-main text-light-error-contrast dark:text-dark-error-contrast',
|
|
112
|
-
secondary: 'bg-light-error-
|
|
114
|
+
secondary: 'bg-light-error-alertBg dark:bg-dark-error-alertBg text-light-error-dark dark:text-dark-error-light',
|
|
113
115
|
tertiary: 'bg-transparent border border-light-error-main dark:border-dark-error-main text-light-error-main dark:text-dark-error-main',
|
|
114
116
|
textOnly: 'text-light-error-main dark:text-dark-error-main',
|
|
115
117
|
},
|
|
@@ -123,7 +125,7 @@ export default function Button(_a) {
|
|
|
123
125
|
},
|
|
124
126
|
danger: {
|
|
125
127
|
primary: 'hover:bg-light-error-dark hover:dark:bg-dark-error-dark',
|
|
126
|
-
secondary: 'hover:bg-light-error-
|
|
128
|
+
secondary: 'hover:bg-light-error-light/60 dark:hover:bg-dark-error-dark/60',
|
|
127
129
|
tertiary: 'hover:bg-light-error-main/10 dark:hover:bg-dark-error-main/10',
|
|
128
130
|
textOnly: 'hover:bg-light-error-main/10 dark:hover:bg-dark-error-main/10',
|
|
129
131
|
},
|
|
@@ -146,9 +148,9 @@ export default function Button(_a) {
|
|
|
146
148
|
{/* Group IconLeft and label in a flex container for left alignment */}
|
|
147
149
|
<div className="flex items-center">
|
|
148
150
|
{IconLeft && <IconLeft className={sizeIcon} strokeWidth={2}/>}
|
|
149
|
-
<div className="flex flex-col text-center px-2
|
|
151
|
+
<div className={"flex flex-col text-center ".concat(size === 'tiny' ? 'px-1' : 'px-2')}>
|
|
150
152
|
<span className="whitespace-nowrap overflow-hidden truncate">{label}</span>
|
|
151
|
-
{secondLabel && (<span className="whitespace-nowrap overflow-hidden truncate text-body2 opacity-70">{secondLabel}</span>)}
|
|
153
|
+
{secondLabel && (<span className={"whitespace-nowrap overflow-hidden truncate ".concat(size === 'tiny' ? 'text-caption' : 'text-body2', " opacity-70")}>{secondLabel}</span>)}
|
|
152
154
|
</div>
|
|
153
155
|
</div>
|
|
154
156
|
{IconRight && (<div onClick={onClickActionIcon} className="cursor-pointer">
|
|
@@ -3,7 +3,7 @@ import { icons } from 'lucide-react';
|
|
|
3
3
|
type IconName = keyof typeof icons;
|
|
4
4
|
interface IconProps {
|
|
5
5
|
name: IconName;
|
|
6
|
-
size?: 'small' | 'medium' | 'large' | number;
|
|
6
|
+
size?: 'tiny' | 'small' | 'medium' | 'large' | number;
|
|
7
7
|
color?: 'primary' | 'secondary' | 'disabled' | 'error' | 'warning' | 'success' | 'info' | 'accent' | 'inherit';
|
|
8
8
|
strokeWidth?: number;
|
|
9
9
|
className?: string;
|
package/dist/components/icon.jsx
CHANGED
|
@@ -3,7 +3,7 @@ import * as LucideIcons from 'lucide-react';
|
|
|
3
3
|
interface IconButtonProps {
|
|
4
4
|
color: "primary" | "secondary" | "tertiary" | "iconOnly";
|
|
5
5
|
state: "enabled" | "selected" | "disabled";
|
|
6
|
-
size: "large" | "medium" | "small";
|
|
6
|
+
size: "large" | "medium" | "small" | "tiny";
|
|
7
7
|
iconName: keyof typeof LucideIcons;
|
|
8
8
|
onClick?: any;
|
|
9
9
|
loading?: boolean;
|
|
@@ -4,8 +4,7 @@ import * as LucideIcons from 'lucide-react';
|
|
|
4
4
|
import { LoadingSmall } from './loadingScreen';
|
|
5
5
|
export default function IconButton(_a) {
|
|
6
6
|
var color = _a.color, state = _a.state, size = _a.size, iconName = _a.iconName, onClick = _a.onClick, _b = _a.loading, loading = _b === void 0 ? false : _b;
|
|
7
|
-
var _c = useState(
|
|
8
|
-
var _d = useState(null), Icon = _d[0], setIcon = _d[1];
|
|
7
|
+
var _c = useState(null), Icon = _c[0], setIcon = _c[1];
|
|
9
8
|
// Load icon from Lucide
|
|
10
9
|
useEffect(function () {
|
|
11
10
|
if (iconName) {
|
|
@@ -17,11 +16,13 @@ export default function IconButton(_a) {
|
|
|
17
16
|
large: 'p-2', // 8px padding
|
|
18
17
|
medium: 'p-1', // 4px padding
|
|
19
18
|
small: 'p-1', // 4px padding
|
|
19
|
+
tiny: 'p-0.5', // 2px padding
|
|
20
20
|
};
|
|
21
21
|
var iconSizeClasses = {
|
|
22
22
|
large: 'size-6', // 24px
|
|
23
23
|
medium: 'size-6', // 24px
|
|
24
24
|
small: 'size-5', // 20px
|
|
25
|
+
tiny: 'size-4', // 16px
|
|
25
26
|
};
|
|
26
27
|
// Base classes (padding and corner radius)
|
|
27
28
|
var baseClasses = "".concat(sizeClasses[size], " rounded-[8px] leading-none relative");
|
|
@@ -39,12 +40,12 @@ export default function IconButton(_a) {
|
|
|
39
40
|
var bgColorHover = state === 'selected'
|
|
40
41
|
? '' // No hover effect when selected
|
|
41
42
|
: color === 'primary'
|
|
42
|
-
? 'hover:bg-light-accent-dark hover:dark:bg-dark-accent-dark' // Primary
|
|
43
|
+
? 'hover:bg-light-accent-dark/75 hover:dark:bg-dark-accent-dark/75' // Primary
|
|
43
44
|
: color === 'secondary'
|
|
44
|
-
? 'hover:bg-light-secondary-dark hover:dark:bg-dark-secondary-dark' // Secondary
|
|
45
|
+
? 'hover:bg-light-secondary-dark/75 hover:dark:bg-dark-secondary-dark/75' // Secondary
|
|
45
46
|
: color === 'tertiary'
|
|
46
|
-
? 'hover:bg-light-background-accent200 hover:dark:bg-dark-background-accent200' // Tertiary
|
|
47
|
-
: 'hover:bg-light-background-accent200 hover:dark:bg-dark-background-accent200'; // iconOnly
|
|
47
|
+
? 'hover:bg-light-background-accent200/75 hover:dark:bg-dark-background-accent200/75' // Tertiary
|
|
48
|
+
: 'hover:bg-light-background-accent200/75 hover:dark:bg-dark-background-accent200/75'; // iconOnly
|
|
48
49
|
// Icon color
|
|
49
50
|
var iconColor = state === 'selected'
|
|
50
51
|
? 'text-light-text-contrast dark:text-dark-text-contrast' // Selected state
|
|
@@ -62,11 +63,9 @@ export default function IconButton(_a) {
|
|
|
62
63
|
? 'cursor-not-allowed opacity-50'
|
|
63
64
|
: state === 'selected'
|
|
64
65
|
? 'cursor-pointer'
|
|
65
|
-
:
|
|
66
|
-
? 'cursor-pointer hover:bg-opacity-75'
|
|
67
|
-
: 'cursor-pointer';
|
|
66
|
+
: 'cursor-pointer';
|
|
68
67
|
return (<button className={"".concat(baseClasses, " ").concat(bgColor, " ").concat(iconColor, " ").concat(bgColorHover, " ").concat(stateClasses, " transition-colors duration-200 ease-in-out flex items-center justify-center")} disabled={state === 'disabled' || loading} // Disable button during loading
|
|
69
|
-
|
|
68
|
+
onClick={onClick} aria-label={loading ? 'Loading' : 'Reload'}>
|
|
70
69
|
{loading ? (<LoadingSmall size={size}/>) : (Icon && <Icon className={iconSizeClasses[size]} strokeWidth={2}/>)}
|
|
71
70
|
</button>);
|
|
72
71
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
interface LoadingSmallProps {
|
|
3
|
-
size?: 'large' | 'medium' | 'small';
|
|
3
|
+
size?: 'large' | 'medium' | 'small' | 'tiny';
|
|
4
4
|
}
|
|
5
5
|
export default function LoadingScreen(): React.JSX.Element;
|
|
6
6
|
export declare function LoadingSmall({ size }: LoadingSmallProps): React.JSX.Element;
|
|
@@ -12,6 +12,7 @@ export function LoadingSmall(_a) {
|
|
|
12
12
|
large: 'w-6 h-6 border-2', // 24px, border-2 for proportional thickness
|
|
13
13
|
medium: 'w-6 h-6 border-2', // 24px, border-2
|
|
14
14
|
small: 'w-5 h-5 border-2', // 20px, slightly thinner border
|
|
15
|
+
tiny: 'w-4 h-4 border-2', // 16px
|
|
15
16
|
};
|
|
16
17
|
return (<div className="flex justify-center items-center">
|
|
17
18
|
<div className={"rounded-full border-t-transparent border-r-light-text-primary border-b-light-text-primary border-l-light-text-primary dark:border-t-transparent dark:border-r-dark-text-primary dark:border-b-dark-text-primary dark:border-l-dark-text-primary animate-spin ".concat(spinnerSizeClasses[size])}/>
|
|
@@ -93,10 +93,12 @@ export default function MenuItem(_a) {
|
|
|
93
93
|
fetchIcon();
|
|
94
94
|
}, [iconName, iconRight, loadIcon]);
|
|
95
95
|
// Size-based icon and text classes
|
|
96
|
-
var iconSize =
|
|
97
|
-
var labelClass =
|
|
98
|
-
var
|
|
99
|
-
var
|
|
96
|
+
var iconSize = { tiny: 'w-4 h-4', small: 'w-5 h-5', medium: 'w-6 h-6' }[size];
|
|
97
|
+
var labelClass = { tiny: 'text-caption', small: 'text-body2', medium: 'text-body1' }[size];
|
|
98
|
+
var secondLabelClass = size === 'tiny' ? 'text-caption' : 'text-body2';
|
|
99
|
+
var tagSize = { tiny: 'tiny', small: 'small', medium: 'medium' }[size];
|
|
100
|
+
var paddingClass = size === 'tiny' ? 'p-1' : 'p-2';
|
|
101
|
+
var content = (<div className={"\n flex items-center ".concat(paddingClass, " rounded-[8px] cursor-pointer justify-between transition-colors duration-200 ease-in-out\n ").concat(isSelected
|
|
100
102
|
? 'bg-light-primary-dark dark:bg-dark-primary-dark text-light-text-contrast dark:text-dark-text-contrast'
|
|
101
103
|
: 'hover:bg-light-background-accent200 hover:dark:bg-dark-background-accent200', "\n ").concat(className, "\n ")} style={{ width: '100%' }} onClick={onClick}>
|
|
102
104
|
{/* Left group: icon/userImg + label with 8px gap */}
|
|
@@ -106,7 +108,7 @@ export default function MenuItem(_a) {
|
|
|
106
108
|
<span className={"truncate ".concat(labelClass, " ").concat(isSelected ? 'text-light-text-contrast dark:text-dark-text-contrast' : 'text-light-text-primary dark:text-dark-text-primary')}>
|
|
107
109
|
{label}
|
|
108
110
|
</span>
|
|
109
|
-
{secondLabel && (<span className={"truncate
|
|
111
|
+
{secondLabel && (<span className={"truncate ".concat(secondLabelClass, " opacity-70 ").concat(isSelected ? 'text-light-text-contrast dark:text-dark-text-contrast' : 'text-light-text-primary dark:text-dark-text-primary')}>
|
|
110
112
|
{secondLabel}
|
|
111
113
|
</span>)}
|
|
112
114
|
</div>
|
package/dist/components/tab.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ type TabProps = {
|
|
|
12
12
|
decoIcon?: string;
|
|
13
13
|
actionIcon?: string;
|
|
14
14
|
router?: RouterLike;
|
|
15
|
+
size?: 'medium' | 'small' | 'tiny';
|
|
15
16
|
};
|
|
16
|
-
export default function Tab({ label, secondLabel, href, isSelected, onClickTab, onClickActionIcon, decoIcon, actionIcon, router }: TabProps): React.JSX.Element;
|
|
17
|
+
export default function Tab({ label, secondLabel, href, isSelected, onClickTab, onClickActionIcon, decoIcon, actionIcon, router, size, }: TabProps): React.JSX.Element;
|
|
17
18
|
export {};
|
package/dist/components/tab.jsx
CHANGED
|
@@ -35,12 +35,14 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
35
35
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
-
import React, { useState, useEffect, useCallback } from 'react';
|
|
38
|
+
import React, { useState, useEffect, useCallback, useContext } from 'react';
|
|
39
|
+
import { TabsContainerContext } from './tabsContainer';
|
|
39
40
|
export default function Tab(_a) {
|
|
40
41
|
var _this = this;
|
|
41
|
-
var label = _a.label, secondLabel = _a.secondLabel, href = _a.href, isSelected = _a.isSelected, onClickTab = _a.onClickTab, onClickActionIcon = _a.onClickActionIcon, decoIcon = _a.decoIcon, actionIcon = _a.actionIcon, router = _a.router;
|
|
42
|
-
var
|
|
43
|
-
var _c = useState(null),
|
|
42
|
+
var label = _a.label, secondLabel = _a.secondLabel, href = _a.href, isSelected = _a.isSelected, onClickTab = _a.onClickTab, onClickActionIcon = _a.onClickActionIcon, decoIcon = _a.decoIcon, actionIcon = _a.actionIcon, router = _a.router, _b = _a.size, size = _b === void 0 ? 'medium' : _b;
|
|
43
|
+
var inContainer = useContext(TabsContainerContext);
|
|
44
|
+
var _c = useState(null), IconLeft = _c[0], setIconLeft = _c[1];
|
|
45
|
+
var _d = useState(null), IconRight = _d[0], setIconRight = _d[1];
|
|
44
46
|
// Load icon dynamically
|
|
45
47
|
var loadIcon = useCallback(function (iconName) { return __awaiter(_this, void 0, void 0, function () {
|
|
46
48
|
var module_1, Icon, error_1;
|
|
@@ -96,20 +98,29 @@ export default function Tab(_a) {
|
|
|
96
98
|
router.push(href);
|
|
97
99
|
}
|
|
98
100
|
};
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
var sizeClasses = {
|
|
102
|
+
medium: { tab: 'py-1 px-[6px]', label: 'px-[6px] text-body1', secondLabel: 'text-body2', icon: 'w-6 h-6' },
|
|
103
|
+
small: { tab: 'py-1 px-[6px]', label: 'px-1 text-body2', secondLabel: 'text-caption', icon: 'w-5 h-5' },
|
|
104
|
+
tiny: { tab: 'py-0.5 px-1', label: 'px-1 text-caption', secondLabel: 'text-caption', icon: 'w-4 h-4' },
|
|
105
|
+
}[size];
|
|
106
|
+
// Inside a TabsContainer the container's sliding pill is the selected background
|
|
107
|
+
var selectedClasses = inContainer
|
|
108
|
+
? 'text-light-text-contrast dark:text-dark-text-contrast'
|
|
109
|
+
: 'bg-light-primary-dark dark:bg-dark-primary-dark text-light-text-contrast dark:text-dark-text-contrast';
|
|
110
|
+
return (<div data-tab-selected={isSelected} className={"\n relative flex items-center space-x-1 rounded-[8px] cursor-pointer justify-start transition-colors duration-200 ease-in-out\n ".concat(sizeClasses.tab, "\n ").concat(isSelected
|
|
111
|
+
? selectedClasses
|
|
101
112
|
: 'text-light-text-primary dark:text-dark-text-primary hover:bg-light-background-accent200 dark:hover:bg-dark-background-accent200', "\n ")} onClick={handleClick}>
|
|
102
|
-
{IconLeft && <IconLeft className=
|
|
103
|
-
<div className="flex flex-col
|
|
104
|
-
<span className="whitespace-nowrap
|
|
113
|
+
{IconLeft && <IconLeft className={sizeClasses.icon} strokeWidth={2}/>}
|
|
114
|
+
<div className={"flex flex-col text-center ".concat(sizeClasses.label)}>
|
|
115
|
+
<span className="whitespace-nowrap">
|
|
105
116
|
{label}
|
|
106
117
|
</span>
|
|
107
|
-
{secondLabel && (<span className="whitespace-nowrap
|
|
118
|
+
{secondLabel && (<span className={"whitespace-nowrap opacity-70 ".concat(sizeClasses.secondLabel)}>
|
|
108
119
|
{secondLabel}
|
|
109
120
|
</span>)}
|
|
110
121
|
</div>
|
|
111
122
|
{IconRight && (<div onClick={onClickActionIcon} className="cursor-pointer">
|
|
112
|
-
<IconRight className=
|
|
123
|
+
<IconRight className={sizeClasses.icon} strokeWidth={2}/>
|
|
113
124
|
</div>)}
|
|
114
125
|
</div>);
|
|
115
126
|
}
|
|
@@ -1,12 +1,76 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { createContext, useLayoutEffect, useRef, useState } from 'react';
|
|
3
|
+
// Lets a Tab know a container draws its selected background (the sliding pill)
|
|
4
|
+
export var TabsContainerContext = createContext(false);
|
|
3
5
|
export default function TabsContainer(_a) {
|
|
4
6
|
var children = _a.children;
|
|
5
7
|
var tabCount = React.Children.count(children);
|
|
6
|
-
|
|
8
|
+
var containerRef = useRef(null);
|
|
9
|
+
var selectedRef = useRef(null);
|
|
10
|
+
var _b = useState(null), indicator = _b[0], setIndicator = _b[1];
|
|
11
|
+
useLayoutEffect(function () {
|
|
12
|
+
var _a;
|
|
13
|
+
var container = containerRef.current;
|
|
14
|
+
if (!container)
|
|
15
|
+
return;
|
|
16
|
+
var update = function () {
|
|
17
|
+
var selected = container.querySelector('[data-tab-selected="true"]');
|
|
18
|
+
if (!selected) {
|
|
19
|
+
selectedRef.current = null;
|
|
20
|
+
setIndicator(null);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
setIndicator(function (prev) { return ({
|
|
24
|
+
animate: prev !== null,
|
|
25
|
+
x: selected.offsetLeft,
|
|
26
|
+
y: selected.offsetTop,
|
|
27
|
+
width: selected.offsetWidth,
|
|
28
|
+
height: selected.offsetHeight,
|
|
29
|
+
}); });
|
|
30
|
+
// Tabs scroll horizontally instead of wrapping; keep a newly selected tab in view
|
|
31
|
+
if (selected !== selectedRef.current) {
|
|
32
|
+
selectedRef.current = selected;
|
|
33
|
+
var left = selected.offsetLeft;
|
|
34
|
+
var right = left + selected.offsetWidth;
|
|
35
|
+
if (left < container.scrollLeft) {
|
|
36
|
+
container.scrollTo({ left: left - 4, behavior: 'smooth' });
|
|
37
|
+
}
|
|
38
|
+
else if (right > container.scrollLeft + container.clientWidth) {
|
|
39
|
+
container.scrollTo({ left: right - container.clientWidth + 4, behavior: 'smooth' });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
update();
|
|
44
|
+
// Tab widths change once web fonts load
|
|
45
|
+
(_a = document.fonts) === null || _a === void 0 ? void 0 : _a.ready.then(update);
|
|
46
|
+
var resizeObserver = new ResizeObserver(update);
|
|
47
|
+
resizeObserver.observe(container);
|
|
48
|
+
Array.from(container.children).forEach(function (child) { return resizeObserver.observe(child); });
|
|
49
|
+
var mutationObserver = new MutationObserver(update);
|
|
50
|
+
mutationObserver.observe(container, {
|
|
51
|
+
subtree: true,
|
|
52
|
+
childList: true,
|
|
53
|
+
attributes: true,
|
|
54
|
+
attributeFilter: ['data-tab-selected'],
|
|
55
|
+
});
|
|
56
|
+
return function () {
|
|
57
|
+
resizeObserver.disconnect();
|
|
58
|
+
mutationObserver.disconnect();
|
|
59
|
+
};
|
|
60
|
+
}, [children]);
|
|
61
|
+
return (<TabsContainerContext.Provider value={true}>
|
|
62
|
+
<div ref={containerRef} className={"\n relative flex gap-2 p-1 rounded-[12px] overflow-x-auto\n ".concat(tabCount > 0 ? 'bg-light-background-accent100 dark:bg-dark-background-accent100' : 'bg-transparent', "\n ")} style={{
|
|
7
63
|
scrollbarWidth: 'none',
|
|
8
64
|
msOverflowStyle: 'none',
|
|
9
65
|
}}>
|
|
10
|
-
|
|
11
|
-
|
|
66
|
+
{indicator && (<span aria-hidden className={"absolute rounded-[8px] pointer-events-none bg-light-primary-dark dark:bg-dark-primary-dark\n ".concat(indicator.animate ? 'transition-[transform,width,height] duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:transition-none' : '')} style={{
|
|
67
|
+
top: 0,
|
|
68
|
+
left: 0,
|
|
69
|
+
transform: "translate(".concat(indicator.x, "px, ").concat(indicator.y, "px)"),
|
|
70
|
+
width: indicator.width,
|
|
71
|
+
height: indicator.height,
|
|
72
|
+
}}/>)}
|
|
73
|
+
{children}
|
|
74
|
+
</div>
|
|
75
|
+
</TabsContainerContext.Provider>);
|
|
12
76
|
}
|
package/dist/components/tag.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { icons } from 'lucide-react';
|
|
|
3
3
|
type IconName = keyof typeof icons;
|
|
4
4
|
interface TagProps {
|
|
5
5
|
variant: 'contained' | 'textOnly' | 'dot';
|
|
6
|
-
size: 'medium' | 'small';
|
|
6
|
+
size: 'medium' | 'small' | 'tiny';
|
|
7
7
|
state?: 'enabled' | 'selected';
|
|
8
8
|
color?: 'default' | 'success' | 'warning' | 'error' | 'info';
|
|
9
9
|
label: React.ReactNode;
|
package/dist/components/tag.jsx
CHANGED
|
@@ -49,7 +49,11 @@ export default function Tag(_a) {
|
|
|
49
49
|
// Get icon directly from icons map
|
|
50
50
|
var Icon = iconName ? icons[iconName] : null;
|
|
51
51
|
// Size and padding
|
|
52
|
-
var sizeClasses =
|
|
52
|
+
var sizeClasses = {
|
|
53
|
+
medium: 'text-body2 px-2 py-1',
|
|
54
|
+
small: 'text-caption px-2 py-[3px]',
|
|
55
|
+
tiny: 'text-caption px-1.5 py-0',
|
|
56
|
+
}[size];
|
|
53
57
|
// Selected state styles
|
|
54
58
|
var isSelected = state === 'selected';
|
|
55
59
|
// When color is provided, use color-based styling
|
|
@@ -112,7 +116,7 @@ export default function Tag(_a) {
|
|
|
112
116
|
var baseClasses = 'flex space-x-2 items-center gap-1 rounded-full whitespace-nowrap transition-colors duration-200 ease-in-out';
|
|
113
117
|
return (<div className={"".concat(baseClasses, " ").concat(sizeClasses, " ").concat(bgClasses, " ").concat(fontClasses, " ").concat(borderClasses, " ").concat(hoverClasses, " ").concat(cursorClass)} onMouseEnter={function () { return onClick && setIsHovered(true); }} onMouseLeave={function () { return onClick && setIsHovered(false); }} onClick={onClick}>
|
|
114
118
|
{variant === 'dot' && (<span className={"w-3 h-3 rounded-full flex-shrink-0 ".concat(dotColor)}/>)}
|
|
115
|
-
{Icon && variant !== 'dot' && <Icon className="w-4 h-4 flex-shrink-0" strokeWidth={2}/>}
|
|
119
|
+
{Icon && variant !== 'dot' && <Icon className={"".concat(size === 'tiny' ? 'w-3 h-3' : 'w-4 h-4', " flex-shrink-0")} strokeWidth={2}/>}
|
|
116
120
|
<div className="flex flex-col text-center">
|
|
117
121
|
<span>{label}</span>
|
|
118
122
|
{secondLabel && (<span className="text-caption opacity-70">{secondLabel}</span>)}
|
|
@@ -15,7 +15,7 @@ interface TextFieldProps {
|
|
|
15
15
|
disabled?: boolean;
|
|
16
16
|
error?: boolean;
|
|
17
17
|
required?: boolean;
|
|
18
|
-
size?: 'large' | 'medium' | 'small';
|
|
18
|
+
size?: 'large' | 'medium' | 'small' | 'tiny';
|
|
19
19
|
placeholder?: string;
|
|
20
20
|
}
|
|
21
21
|
export default function TextField({ id, label, value, type, onChange, onBlur, onFocus, onKeyDown, onSubmit, autoFocus, multiline, maxRows, disabled, error, required, size, placeholder, }: TextFieldProps): React.JSX.Element;
|
|
@@ -17,6 +17,7 @@ export default function TextField(_a) {
|
|
|
17
17
|
large: 'text-body1 p-2 leading-[22px]', // body1 (16px), padding 8px
|
|
18
18
|
medium: 'text-body1 p-2 leading-[22px]', // body1 (16px), padding 8px
|
|
19
19
|
small: 'text-body2 p-2 leading-[18px]', // body2 (14px), padding 8px
|
|
20
|
+
tiny: 'text-caption p-1 leading-[16px]', // caption (12px), padding 4px
|
|
20
21
|
}[size];
|
|
21
22
|
var baseClasses = 'w-full border rounded-[8px] outline-none';
|
|
22
23
|
var textColor = 'text-light-text-primary dark:text-dark-text-primary';
|
|
@@ -14,7 +14,7 @@ interface TextareaProps {
|
|
|
14
14
|
maxRows?: number;
|
|
15
15
|
disabled?: boolean;
|
|
16
16
|
error?: boolean;
|
|
17
|
-
size?: 'medium' | 'small';
|
|
17
|
+
size?: 'medium' | 'small' | 'tiny';
|
|
18
18
|
placeholder?: string;
|
|
19
19
|
}
|
|
20
20
|
export default function Textarea({ id, label, value, onChange, onBlur, onFocus, onKeyDown, onCompositionStart, onCompositionEnd, onSubmit, autoFocus, maxRows, disabled, error, size, placeholder, }: TextareaProps): React.JSX.Element;
|
|
@@ -39,6 +39,7 @@ export default function Textarea(_a) {
|
|
|
39
39
|
var sizeClasses = {
|
|
40
40
|
medium: 'text-body1 p-2 leading-[22px]', // body1 (16px), padding 8px
|
|
41
41
|
small: 'text-body2 p-2 leading-[18px]', // body2 (14px), padding 8px
|
|
42
|
+
tiny: 'text-caption p-1 leading-[16px]', // caption (12px), padding 4px
|
|
42
43
|
}[size];
|
|
43
44
|
var baseClasses = 'w-full border rounded-[8px] outline-none [&::-webkit-scrollbar]:hidden';
|
|
44
45
|
var textColor = 'text-light-text-primary dark:text-dark-text-primary';
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React, { useState, useRef,
|
|
2
|
+
import React, { useState, useRef, useLayoutEffect } from 'react';
|
|
3
|
+
var VIEWPORT_MARGIN = 8;
|
|
3
4
|
export default function Tooltip(_a) {
|
|
4
5
|
var title = _a.title, children = _a.children, placement = _a.placement;
|
|
5
6
|
var _b = useState(false), visible = _b[0], setVisible = _b[1];
|
|
6
7
|
var _c = useState(placement !== null && placement !== void 0 ? placement : 'bottom'), position = _c[0], setPosition = _c[1];
|
|
8
|
+
var _d = useState(0), shiftX = _d[0], setShiftX = _d[1];
|
|
7
9
|
var tooltipRef = useRef(null);
|
|
8
10
|
var buttonRef = useRef(null);
|
|
9
|
-
|
|
11
|
+
useLayoutEffect(function () {
|
|
12
|
+
if (!visible)
|
|
13
|
+
return;
|
|
10
14
|
var handlePosition = function () {
|
|
11
15
|
if (tooltipRef.current && buttonRef.current) {
|
|
12
16
|
var tooltipRect = tooltipRef.current.getBoundingClientRect();
|
|
@@ -15,18 +19,28 @@ export default function Tooltip(_a) {
|
|
|
15
19
|
if (placement) {
|
|
16
20
|
setPosition(placement);
|
|
17
21
|
}
|
|
18
|
-
else if (window.innerHeight - buttonRect.bottom < tooltipRect.height + 8) {
|
|
19
|
-
setPosition('top');
|
|
20
|
-
}
|
|
21
22
|
else {
|
|
22
|
-
|
|
23
|
+
var spaceBelow = window.innerHeight - buttonRect.bottom;
|
|
24
|
+
var fitsBelow = spaceBelow >= tooltipRect.height + VIEWPORT_MARGIN;
|
|
25
|
+
var fitsAbove = buttonRect.top >= tooltipRect.height + VIEWPORT_MARGIN;
|
|
26
|
+
setPosition(!fitsBelow && fitsAbove ? 'top' : 'bottom');
|
|
23
27
|
}
|
|
28
|
+
// Keep the tooltip inside the viewport horizontally
|
|
29
|
+
var centerX = buttonRect.left + buttonRect.width / 2;
|
|
30
|
+
var half = tooltipRect.width / 2;
|
|
31
|
+
var minCenter = VIEWPORT_MARGIN + half;
|
|
32
|
+
var maxCenter = window.innerWidth - VIEWPORT_MARGIN - half;
|
|
33
|
+
setShiftX(Math.min(Math.max(centerX, minCenter), maxCenter) - centerX);
|
|
24
34
|
}
|
|
25
35
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
handlePosition();
|
|
37
|
+
window.addEventListener('resize', handlePosition);
|
|
38
|
+
window.addEventListener('scroll', handlePosition, true);
|
|
39
|
+
return function () {
|
|
40
|
+
window.removeEventListener('resize', handlePosition);
|
|
41
|
+
window.removeEventListener('scroll', handlePosition, true);
|
|
42
|
+
};
|
|
43
|
+
}, [visible, placement, title]);
|
|
30
44
|
var handleClick = function () {
|
|
31
45
|
setVisible(false); // Hide tooltip on click
|
|
32
46
|
};
|
|
@@ -36,7 +50,7 @@ export default function Tooltip(_a) {
|
|
|
36
50
|
bottom: position === 'top' ? '100%' : undefined,
|
|
37
51
|
top: position === 'bottom' ? '100%' : undefined,
|
|
38
52
|
left: '50%',
|
|
39
|
-
transform:
|
|
53
|
+
transform: "translateX(calc(-50% + ".concat(shiftX, "px))"),
|
|
40
54
|
}}>
|
|
41
55
|
{title}
|
|
42
56
|
</div>)}
|
package/dist/designTokens.js
CHANGED
|
@@ -175,13 +175,13 @@ module.exports = {
|
|
|
175
175
|
typography: {
|
|
176
176
|
family: 'Inter, sans-serif',
|
|
177
177
|
h1: {
|
|
178
|
-
weight: '
|
|
178
|
+
weight: '400',
|
|
179
179
|
size: '96px',
|
|
180
180
|
lineHeight: '120%',
|
|
181
181
|
letterSpacing: '-1.5px',
|
|
182
182
|
},
|
|
183
183
|
h2: {
|
|
184
|
-
weight: '
|
|
184
|
+
weight: '400',
|
|
185
185
|
size: '60px',
|
|
186
186
|
lineHeight: '120%',
|
|
187
187
|
letterSpacing: '-0.5px',
|
|
@@ -205,19 +205,19 @@ module.exports = {
|
|
|
205
205
|
letterSpacing: '0px',
|
|
206
206
|
},
|
|
207
207
|
h6: {
|
|
208
|
-
weight: '
|
|
208
|
+
weight: '400',
|
|
209
209
|
size: '20px',
|
|
210
210
|
lineHeight: '150%',
|
|
211
211
|
letterSpacing: '0.2px',
|
|
212
212
|
},
|
|
213
213
|
subtitle1: {
|
|
214
|
-
weight: '
|
|
214
|
+
weight: '400',
|
|
215
215
|
size: '16px',
|
|
216
216
|
lineHeight: '150%',
|
|
217
217
|
letterSpacing: '0.2px',
|
|
218
218
|
},
|
|
219
219
|
subtitle2: {
|
|
220
|
-
weight: '
|
|
220
|
+
weight: '400',
|
|
221
221
|
size: '14px',
|
|
222
222
|
lineHeight: '150%',
|
|
223
223
|
letterSpacing: '0.1px',
|