@apify/ui-library 0.71.1-featcolortokens-178953.58 → 0.71.1-featcolortokens-178953.67

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 (121) hide show
  1. package/dist/src/design_system/colors/generated/{dark.d.ts → css_variables.dark.d.ts} +1 -1
  2. package/dist/src/design_system/colors/generated/css_variables.dark.d.ts.map +1 -0
  3. package/dist/src/design_system/colors/generated/css_variables.dark.js +147 -0
  4. package/dist/src/design_system/colors/generated/css_variables.dark.js.map +1 -0
  5. package/dist/src/design_system/colors/generated/{light.d.ts → css_variables.light.d.ts} +1 -1
  6. package/dist/src/design_system/colors/generated/css_variables.light.d.ts.map +1 -0
  7. package/dist/src/design_system/colors/generated/css_variables.light.js +147 -0
  8. package/dist/src/design_system/colors/generated/css_variables.light.js.map +1 -0
  9. package/dist/src/design_system/colors/generated/{palette.dark.d.ts → css_variables_palette.dark.d.ts} +1 -1
  10. package/dist/src/design_system/colors/generated/css_variables_palette.dark.d.ts.map +1 -0
  11. package/dist/src/design_system/colors/generated/css_variables_palette.dark.js +74 -0
  12. package/dist/src/design_system/colors/generated/css_variables_palette.dark.js.map +1 -0
  13. package/dist/src/design_system/colors/generated/{palette.light.d.ts → css_variables_palette.light.d.ts} +1 -1
  14. package/dist/src/design_system/colors/generated/css_variables_palette.light.d.ts.map +1 -0
  15. package/dist/src/design_system/colors/generated/css_variables_palette.light.js +74 -0
  16. package/dist/src/design_system/colors/generated/css_variables_palette.light.js.map +1 -0
  17. package/dist/src/design_system/colors/index.d.ts +4 -4
  18. package/dist/src/design_system/colors/index.d.ts.map +1 -1
  19. package/dist/src/design_system/colors/index.js +4 -4
  20. package/dist/src/design_system/colors/index.js.map +1 -1
  21. package/dist/tsconfig.build.tsbuildinfo +1 -1
  22. package/package.json +3 -2
  23. package/src/codemods/generate_typograpy_tokens_files.mjs +137 -0
  24. package/src/components/action_link.tsx +60 -0
  25. package/src/components/actor_template_card.tsx +116 -0
  26. package/src/components/badge.tsx +148 -0
  27. package/src/components/banner.tsx +94 -0
  28. package/src/components/blog_article.tsx +85 -0
  29. package/src/components/box.tsx +127 -0
  30. package/src/components/button.tsx +305 -0
  31. package/src/components/chip.tsx +128 -0
  32. package/src/components/code/action_button.tsx +96 -0
  33. package/src/components/code/code_block/code_block.styled.tsx +180 -0
  34. package/src/components/code/code_block/code_block.tsx +224 -0
  35. package/src/components/code/code_block/code_block_with_tabs.tsx +257 -0
  36. package/src/components/code/code_block/utils.tsx +67 -0
  37. package/src/components/code/index.ts +5 -0
  38. package/src/components/code/inline_code/inline_code.tsx +62 -0
  39. package/src/components/code/one_line_code/one_line_code.tsx +228 -0
  40. package/src/components/code/prism_highlighter.tsx +180 -0
  41. package/src/components/color_wheel_gradient.tsx +31 -0
  42. package/src/components/floating/index.ts +3 -0
  43. package/src/components/floating/menu.tsx +189 -0
  44. package/src/components/floating/menu_common.tsx +31 -0
  45. package/src/components/floating/menu_components.tsx +99 -0
  46. package/src/components/image.tsx +24 -0
  47. package/src/components/index.ts +22 -0
  48. package/src/components/link.tsx +114 -0
  49. package/src/components/message.tsx +153 -0
  50. package/src/components/rating.tsx +106 -0
  51. package/src/components/readme_renderer/index.ts +3 -0
  52. package/src/components/readme_renderer/pythonize_value.ts +76 -0
  53. package/src/components/readme_renderer/table_of_contents.tsx +272 -0
  54. package/src/components/readme_renderer/utils.tsx +46 -0
  55. package/src/components/simple_markdown/index.ts +2 -0
  56. package/src/components/simple_markdown/simple_markdown.tsx +214 -0
  57. package/src/components/simple_markdown/simple_markdown_components.tsx +293 -0
  58. package/src/components/tabs/index.ts +2 -0
  59. package/src/components/tabs/tab.tsx +217 -0
  60. package/src/components/tabs/tabs.tsx +169 -0
  61. package/src/components/tag.tsx +196 -0
  62. package/src/components/text/heading_content.tsx +56 -0
  63. package/src/components/text/heading_marketing.tsx +55 -0
  64. package/src/components/text/heading_shared.tsx +55 -0
  65. package/src/components/text/index.ts +19 -0
  66. package/src/components/text/text_base.tsx +52 -0
  67. package/src/components/text/text_content.tsx +104 -0
  68. package/src/components/text/text_marketing.tsx +152 -0
  69. package/src/components/text/text_shared.tsx +95 -0
  70. package/src/components/tile/horizontal_tile.tsx +77 -0
  71. package/src/components/tile/index.ts +2 -0
  72. package/src/components/tile/shared.ts +27 -0
  73. package/src/components/tile/vertical_tile.tsx +59 -0
  74. package/src/components/to_consolidate/card.tsx +141 -0
  75. package/src/components/to_consolidate/index.ts +4 -0
  76. package/src/components/to_consolidate/markdown.tsx +609 -0
  77. package/src/components/to_consolidate/pagination.tsx +136 -0
  78. package/src/components/to_consolidate/tab_number_chip.tsx +31 -0
  79. package/src/design_system/colors/build_color_tokens.js +183 -0
  80. package/src/design_system/colors/figma_color_tokens.dark.json +886 -0
  81. package/src/design_system/colors/figma_color_tokens.light.json +886 -0
  82. package/src/design_system/colors/generated/colors_theme.dark.ts +110 -0
  83. package/src/design_system/colors/generated/colors_theme.light.ts +110 -0
  84. package/{dist/src/design_system/colors/generated/dark.js → src/design_system/colors/generated/css_variables.dark.ts} +1 -1
  85. package/{dist/src/design_system/colors/generated/light.js → src/design_system/colors/generated/css_variables.light.ts} +1 -1
  86. package/{dist/src/design_system/colors/generated/palette.dark.js → src/design_system/colors/generated/css_variables_palette.dark.ts} +1 -1
  87. package/{dist/src/design_system/colors/generated/palette.light.js → src/design_system/colors/generated/css_variables_palette.light.ts} +1 -1
  88. package/{dist/src/design_system/properties_theme.js → src/design_system/colors/generated/properties_theme.ts} +20 -156
  89. package/src/design_system/colors/index.ts +7 -0
  90. package/src/design_system/supernova_typography_tokens.json +657 -0
  91. package/src/design_system/theme.ts +25 -0
  92. package/src/design_system/tokens/index.ts +5 -0
  93. package/src/design_system/tokens/layouts.ts +29 -0
  94. package/src/design_system/tokens/radiuses.ts +22 -0
  95. package/src/design_system/tokens/shadows.ts +22 -0
  96. package/src/design_system/tokens/spaces.ts +15 -0
  97. package/src/design_system/tokens/transitions.ts +19 -0
  98. package/src/design_system/typography_theme.ts +197 -0
  99. package/src/index.ts +8 -0
  100. package/src/type_utils.ts +7 -0
  101. package/src/ui_dependency_provider.tsx +58 -0
  102. package/src/utils/copy_to_clipboard.ts +24 -0
  103. package/src/utils/image_color.ts +42 -0
  104. package/src/utils/index.ts +4 -0
  105. package/src/utils/resize_observer.ts +18 -0
  106. package/src/utils/sanitization.ts +14 -0
  107. package/dist/src/design_system/colors/generated/dark.d.ts.map +0 -1
  108. package/dist/src/design_system/colors/generated/dark.js.map +0 -1
  109. package/dist/src/design_system/colors/generated/light.d.ts.map +0 -1
  110. package/dist/src/design_system/colors/generated/light.js.map +0 -1
  111. package/dist/src/design_system/colors/generated/palette.dark.d.ts.map +0 -1
  112. package/dist/src/design_system/colors/generated/palette.dark.js.map +0 -1
  113. package/dist/src/design_system/colors/generated/palette.light.d.ts.map +0 -1
  114. package/dist/src/design_system/colors/generated/palette.light.js.map +0 -1
  115. package/dist/src/design_system/colors_theme.d.ts +0 -213
  116. package/dist/src/design_system/colors_theme.d.ts.map +0 -1
  117. package/dist/src/design_system/colors_theme.js +0 -213
  118. package/dist/src/design_system/colors_theme.js.map +0 -1
  119. package/dist/src/design_system/properties_theme.d.ts +0 -175
  120. package/dist/src/design_system/properties_theme.d.ts.map +0 -1
  121. package/dist/src/design_system/properties_theme.js.map +0 -1
@@ -0,0 +1,217 @@
1
+ import clsx from 'clsx';
2
+ import { createPath } from 'history';
3
+ import React from 'react';
4
+ import type { FlattenSimpleInterpolation } from 'styled-components';
5
+ import styled, { css } from 'styled-components';
6
+
7
+ import type { IconComponent } from '@apify/ui-icons';
8
+
9
+ import { theme } from '../../design_system/theme.js';
10
+ import type { WithTransientProps } from '../../type_utils.js';
11
+ import type { BadgeSize } from '../badge.js';
12
+ import { Badge } from '../badge.js';
13
+ import type { MarginSpacingProps, RegularBoxProps } from '../box.js';
14
+ import type { RegularLinkProps } from '../link.js';
15
+ import { Link } from '../link.js';
16
+ import { Text } from '../text/index.js';
17
+ import type { SharedTextSize } from '../text/text_shared.js';
18
+
19
+ type SharedTabProps = Omit<RegularBoxProps, 'as' | 'onClick'> & MarginSpacingProps & Omit<RegularLinkProps, 'hideExternalIcon' | 'showExternalIcon'>;
20
+
21
+ export type TabVariant = 'default' | 'boxed' | 'buttoned';
22
+
23
+ export type TabData = SharedTabProps & {
24
+ id: string;
25
+ title: string;
26
+ Icon?: IconComponent;
27
+ chip?: number | string;
28
+ rollout?: 'alpha' | 'beta';
29
+ disabled?: boolean;
30
+ };
31
+
32
+ export type TabProps = TabData & {
33
+ variant?: TabVariant;
34
+ active?: boolean;
35
+ onSelect?: (data: { id: string, href: string, event: React.MouseEvent }) => void;
36
+ };
37
+
38
+ const tabVariantTextSize = {
39
+ default: 'regular',
40
+ boxed: 'regular',
41
+ buttoned: 'small',
42
+ } satisfies Record<TabVariant, SharedTextSize>;
43
+
44
+ const tabVariantBadgeSize = {
45
+ default: 'small',
46
+ boxed: 'small',
47
+ buttoned: 'extra_small',
48
+ } satisfies Record<TabVariant, BadgeSize>;
49
+
50
+ const tabVariantStyle = {
51
+ default: css`
52
+ height: 3.6rem;
53
+ padding: 0 ${theme.space.space8};
54
+ color: ${theme.color.neutral.textSubtle};
55
+
56
+ &:hover {
57
+ color: ${theme.color.primaryBlack.actionHover}
58
+ }
59
+
60
+ &.active {
61
+ color: ${theme.color.neutral.text};
62
+
63
+ &::after {
64
+ bottom: -${theme.space.space4};
65
+ right: 0;
66
+ left: 0;
67
+ height: 2px;
68
+ background-color: ${theme.color.primaryBlack.action};
69
+ border-radius: ${theme.radius.radiusFull};
70
+ content: '';
71
+ display: block;
72
+ pointer-events: none;
73
+ position: absolute;
74
+ }
75
+
76
+ &.disabled::after {
77
+ background-color: ${theme.color.neutral.textDisabled};
78
+ }
79
+ }
80
+ `,
81
+ boxed: css`
82
+ height: 3.6rem;
83
+ border: 1px solid transparent;
84
+ border-top-right-radius: ${theme.radius.radius6};
85
+ border-top-left-radius: ${theme.radius.radius6};
86
+ padding: 0 ${theme.space.space12};
87
+ color: ${theme.color.neutral.textMuted};
88
+
89
+ &::after {
90
+ inset: ${theme.space.space4};
91
+ background-color: transparent;
92
+ border-radius: ${theme.radius.radius6};
93
+ content: '';
94
+ display: block;
95
+ pointer-events: none;
96
+ position: absolute;
97
+ transition: background-color ${theme.transition.fastEaseOut};
98
+ z-index: -1;
99
+ }
100
+
101
+ &:hover {
102
+ color: ${theme.color.neutral.text};
103
+
104
+ &::after {
105
+ background-color: ${theme.color.neutral.hover};
106
+ }
107
+ }
108
+
109
+ &.active {
110
+ color: ${theme.color.neutral.text};
111
+ border-color: ${theme.color.neutral.border};
112
+ border-bottom-color: ${theme.color.neutral.background};
113
+
114
+ &::after {
115
+ background-color: transparent;
116
+ }
117
+ }
118
+ `,
119
+ buttoned: css`
120
+ height: 3.2rem;
121
+ margin: 0 ${theme.space.space4};
122
+ padding: 0 ${theme.space.space8};
123
+ background-color: transparent;
124
+ border: 1px solid transparent;
125
+ border-radius: ${theme.radius.radius8};
126
+ color: ${theme.color.neutral.textMuted};
127
+
128
+ &:hover {
129
+ background-color: ${theme.color.neutral.hover};
130
+ color: ${theme.color.neutral.text};
131
+ }
132
+
133
+ &.active {
134
+ background-color: transparent;
135
+ border-color: ${theme.color.neutral.border};
136
+ color: ${theme.color.neutral.text};
137
+ }
138
+ `,
139
+ } satisfies Record<TabVariant, FlattenSimpleInterpolation>;
140
+
141
+ type TabWrapperProps = WithTransientProps<Required<Pick<TabProps, 'variant'>>> & {
142
+ role?: React.AriaRole;
143
+ };
144
+
145
+ export const TAB_CLASSNAMES = {
146
+ ICON: 'Tab-icon',
147
+ TITLE: 'Tab-title',
148
+ BADGE: 'Tab-badge',
149
+ };
150
+
151
+ const TabWrapper = styled(Link)<TabWrapperProps>`
152
+ display: inline-flex;
153
+ align-items: center;
154
+ justify-content: center;
155
+ gap: ${theme.space.space4};
156
+ flex-shrink: 0;
157
+ cursor: pointer;
158
+ position: relative;
159
+ transition: background-color ${theme.transition.fastEaseOut}, border-color ${theme.transition.fastEaseOut}, color ${theme.transition.fastEaseOut};
160
+ z-index: 1;
161
+
162
+
163
+ ${({ $variant }) => tabVariantStyle[$variant]};
164
+
165
+ &.disabled {
166
+ color: ${theme.color.neutral.textDisabled};
167
+ pointer-events: none;
168
+ }
169
+
170
+ .${TAB_CLASSNAMES.ICON} {
171
+ color: inherit;
172
+ flex-shrink: 0;
173
+ transition: color ${theme.transition.fastEaseOut};
174
+ }
175
+
176
+ .${TAB_CLASSNAMES.TITLE} {
177
+ overflow: hidden;
178
+ text-overflow: ellipsis;
179
+ white-space: nowrap;
180
+ }
181
+
182
+ .${TAB_CLASSNAMES.BADGE} {
183
+ flex-shrink: 0;
184
+ text-transform: uppercase;
185
+ }
186
+ `;
187
+
188
+ export const Tab = ({ variant = 'default', id, to, Icon, title, chip, rollout, className, onSelect, active = false, disabled = false, ...props }: TabProps) => {
189
+ const href = typeof (to) === 'string' ? to : createPath(to);
190
+
191
+ return (
192
+ <TabWrapper
193
+ {...props}
194
+ id={id}
195
+ to={to}
196
+ role="tab"
197
+ data-test="tab"
198
+ data-test-url={href}
199
+ className={clsx(className, { active, disabled })}
200
+ onClick={onSelect ? (event) => onSelect({ id, href, event }) : undefined}
201
+ $variant={variant}
202
+ >
203
+ {Icon && <Icon size="16" className={TAB_CLASSNAMES.ICON} />}
204
+ <Text size={tabVariantTextSize[variant]} className={TAB_CLASSNAMES.ICON} weight="bold" as="div">{title}</Text>
205
+ {chip && (
206
+ <Badge
207
+ size={tabVariantBadgeSize[variant]}
208
+ variant={active ? 'primary_black' : 'neutral_subtle'}
209
+ className={TAB_CLASSNAMES.ICON}
210
+ >
211
+ {chip}
212
+ </Badge>
213
+ )}
214
+ {rollout && <Badge size={tabVariantBadgeSize[variant]} variant="primary_blue" className={TAB_CLASSNAMES.ICON}>{rollout}</Badge>}
215
+ </TabWrapper>
216
+ );
217
+ };
@@ -0,0 +1,169 @@
1
+ import React, { useCallback, useRef, useState } from 'react';
2
+ import type { FlattenSimpleInterpolation } from 'styled-components';
3
+ import styled, { css } from 'styled-components';
4
+
5
+ import { theme } from '../../design_system/theme.js';
6
+ import type { WithTransientProps } from '../../type_utils.js';
7
+ import { useResizeObserverSsr } from '../../utils/resize_observer.js';
8
+ import type { MarginSpacingProps, RegularBoxProps } from '../box.js';
9
+ import { Box } from '../box.js';
10
+ import type { TabData, TabVariant } from './tab.js';
11
+ import { Tab } from './tab.js';
12
+
13
+ type SharedTabsProps = Omit<RegularBoxProps, 'as' | 'onClick'> & MarginSpacingProps;
14
+ type TabsProps = SharedTabsProps & {
15
+ variant?: TabVariant;
16
+ tabs: TabData[];
17
+ activeTab?: string;
18
+ onSelect?: (data: { id: string, href: string, event: React.MouseEvent }) => void;
19
+ };
20
+
21
+ const tabsVariantStyle = {
22
+ default: css`
23
+ align-items: flex-start;
24
+ gap: ${theme.space.space8};
25
+
26
+ &::after {
27
+ bottom: 0;
28
+ right: 0;
29
+ left: 0;
30
+ height: 1px;
31
+ background-color: ${theme.color.neutral.separatorSubtle};
32
+ border-radius: ${theme.radius.radiusFull};
33
+ content: '';
34
+ display: block;
35
+ pointer-events: none;
36
+ position: absolute;
37
+ }
38
+ `,
39
+ boxed: css`
40
+ align-items: flex-end;
41
+
42
+ &::after {
43
+ bottom: 0;
44
+ right: 0;
45
+ left: 0;
46
+ height: 1px;
47
+ background-color: ${theme.color.neutral.border};
48
+ content: '';
49
+ display: block;
50
+ pointer-events: none;
51
+ position: absolute;
52
+ }
53
+ `,
54
+ buttoned: css`
55
+ align-items: center;
56
+ `,
57
+ } satisfies Record<TabVariant, FlattenSimpleInterpolation>;
58
+
59
+ type TabsWrapperProps = WithTransientProps<Required<Pick<TabsProps, 'variant'>>> & {
60
+ role?: React.AriaRole;
61
+ };
62
+
63
+ const TabsWrapper = styled(Box)<TabsWrapperProps>`
64
+ height: 4rem;
65
+ display: flex;
66
+ position: relative;
67
+
68
+ [role='tabpanel'] {
69
+ min-width: 0;
70
+ display: flex;
71
+ flex-grow: 1;
72
+ overflow-x: auto;
73
+ ${({ $variant }) => tabsVariantStyle[$variant]};
74
+
75
+ /* Scrollbar */
76
+ -ms-overflow-style: none;
77
+ scrollbar-width: none;
78
+
79
+ &::-webkit-scrollbar {
80
+ display: none; /* Chrome, Safari, Opera */
81
+ }
82
+ }
83
+
84
+ & > [role="cell"] {
85
+ position: sticky;
86
+ top: 0;
87
+ height: 100%;
88
+ width: 0;
89
+ margin-left: auto;
90
+ opacity: 0;
91
+ transition: opacity ${theme.transition.fastEaseOut};
92
+ z-index: 2;
93
+
94
+ &[aria-hidden="false"] {
95
+ opacity: 1;
96
+ }
97
+
98
+ &::after {
99
+ height: 100%;
100
+ width: ${theme.space.space32};
101
+ content: ' ';
102
+ pointer-events: none;
103
+ position: absolute;
104
+ }
105
+
106
+ &:first-of-type {
107
+ left: 0;
108
+
109
+ &::after {
110
+ left: 0;
111
+ background: linear-gradient(90deg, ${theme.color.neutral.background} 0%, rgba(255, 255, 255, 0) 100%);
112
+ }
113
+ }
114
+
115
+ &:last-of-type {
116
+ right: 0;
117
+
118
+ &::after {
119
+ right: 0;
120
+ background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, ${theme.color.neutral.background} 100%);
121
+ }
122
+ }
123
+ }
124
+ `;
125
+
126
+ type TabOverflowState = {
127
+ right: boolean;
128
+ left: boolean;
129
+ }
130
+
131
+ const isTabsOverflowing = (node: HTMLDivElement): TabOverflowState => {
132
+ if (node.scrollWidth > node.clientWidth) {
133
+ return {
134
+ right: node.clientWidth + node.scrollLeft < node.scrollWidth,
135
+ left: node.scrollLeft > 0,
136
+ };
137
+ }
138
+
139
+ return {
140
+ right: false,
141
+ left: false,
142
+ };
143
+ };
144
+
145
+ export const Tabs = ({ variant = 'default', tabs, activeTab, onSelect, ...props }: TabsProps) => {
146
+ const ref = useRef<HTMLDivElement>(null);
147
+ const [overflowState, setOveflowState] = useState<TabOverflowState>();
148
+
149
+ useResizeObserverSsr(ref, (entry) => setOveflowState(isTabsOverflowing(entry.target as HTMLDivElement)));
150
+ const scrollHandler = useCallback((event: React.SyntheticEvent<HTMLDivElement>) => {
151
+ setOveflowState(isTabsOverflowing(event.currentTarget as HTMLDivElement));
152
+ }, []);
153
+
154
+ return <TabsWrapper {...props} role="tablist" data-test="tabs-wrapper" $variant={variant}>
155
+ <div role="cell" aria-hidden={!overflowState?.left} />
156
+ <div ref={ref} role="tabpanel" onScroll={scrollHandler}>
157
+ {tabs.map((tab) => (
158
+ <Tab
159
+ {...tab}
160
+ key={tab.id}
161
+ variant={variant}
162
+ active={tab.id === activeTab}
163
+ onSelect={onSelect}
164
+ />
165
+ ))}
166
+ </div>
167
+ <div role="cell" aria-hidden={!overflowState?.right} />
168
+ </TabsWrapper>;
169
+ };
@@ -0,0 +1,196 @@
1
+ import React, { type ForwardedRef, forwardRef } from 'react';
2
+ import styled, { css, type FlattenSimpleInterpolation } from 'styled-components';
3
+
4
+ import type { IconComponent, IconSize } from '@apify/ui-icons';
5
+
6
+ import { theme } from '../design_system/theme.js';
7
+ import type { WithTransientProps } from '../type_utils.js';
8
+ import { Box, type MarginSpacingProps, type RegularBoxProps } from './box.js';
9
+ import type { RegularButtonProps } from './button.js';
10
+ import { Link, type RegularLinkProps } from './link.js';
11
+ import { Text } from './text/index.js';
12
+ import { type SharedTextSize, type SharedTextType } from './text/text_shared.js';
13
+
14
+ type TagSize = SharedTextSize;
15
+ export const TAG_SIZES: TagSize[] = ['big', 'regular', 'small'];
16
+
17
+ const TAG_ICON_SIZES = {
18
+ big: '20',
19
+ regular: '16',
20
+ small: '12',
21
+ } satisfies Record<TagSize, IconSize>;
22
+
23
+ export const TAG_VARIANTS = ['primary', 'secondary', 'subtle', 'accent', 'success', 'warning', 'error'] as const;
24
+ type TagVariant = typeof TAG_VARIANTS[number];
25
+
26
+ type TagNodeType = Extract<React.ElementType, 'a' | 'button'>;
27
+ type TagNodePropsMap = {
28
+ a: {
29
+ element: HTMLAnchorElement;
30
+ props: RegularLinkProps;
31
+ };
32
+ button: {
33
+ element: HTMLButtonElement;
34
+ props: RegularButtonProps;
35
+ };
36
+ }
37
+
38
+ type SharedTagProps = Omit<RegularBoxProps, 'as'> & MarginSpacingProps;
39
+ export type TagProps<T extends TagNodeType> = SharedTagProps & ({
40
+ as?: T;
41
+ size?: TagSize;
42
+ type?: SharedTextType;
43
+ variant?: TagVariant;
44
+ LeadingIcon?: IconComponent;
45
+ TrailingIcon?: IconComponent;
46
+ } & Omit<TagNodePropsMap[T]['props'], 'size'>);
47
+
48
+ const tagSizeStyle = {
49
+ big: css`
50
+ height: 4rem;
51
+ padding: ${theme.space.space8} ${theme.space.space12};
52
+ border-radius: ${theme.radius.radius12};
53
+ `,
54
+ regular: css`
55
+ height: 2.8rem;
56
+ padding: ${theme.space.space4} ${theme.space.space8};
57
+ border-radius: ${theme.radius.radius8};
58
+ `,
59
+ small: css`
60
+ height: 2rem;
61
+ padding: ${theme.space.space2} ${theme.space.space6};
62
+ border-radius: ${theme.radius.radius4};
63
+
64
+ &:has(> svg:last-child:nth-child(1)) {
65
+ padding: ${theme.space.space2} ${theme.space.space4};
66
+ }
67
+ `,
68
+ } satisfies Record<TagSize, FlattenSimpleInterpolation>;
69
+
70
+ const tagVariantStyle = {
71
+ primary: css`
72
+ color: ${theme.color.neutral.text};
73
+ fill: ${theme.color.neutral.icon};
74
+ background: transparent;
75
+ box-shadow: inset 0 0 0 1px ${theme.color.neutral.border};
76
+
77
+ &:hover {
78
+ background: ${theme.color.neutral.hover};
79
+ }
80
+ `,
81
+ secondary: css`
82
+ color: ${theme.color.neutral.text};
83
+ fill: ${theme.color.neutral.icon};
84
+ background: transparent;
85
+
86
+ &:hover {
87
+ background: ${theme.color.neutral.hover};
88
+ }
89
+ `,
90
+ subtle: css`
91
+ color: ${theme.color.neutral.text};
92
+ fill: ${theme.color.neutral.icon};
93
+ background: ${theme.color.neutral.backgroundSubtle};
94
+
95
+ &:hover {
96
+ background: ${theme.color.neutral.hover};
97
+ }
98
+ `,
99
+ accent: css`
100
+ color: ${theme.color.primary.chipText};
101
+ fill: ${theme.color.primary.chipText};
102
+ background: ${theme.color.primary.background};
103
+
104
+ &:hover {
105
+ background: ${theme.color.primary.backgroundHover};
106
+ }
107
+ `,
108
+ success: css`
109
+ color: ${theme.color.success.chipText};
110
+ fill: ${theme.color.success.chipText};
111
+ background: ${theme.color.success.background};
112
+
113
+ &:hover {
114
+ background: ${theme.color.success.backgroundHover};
115
+ }
116
+ `,
117
+ warning: css`
118
+ color: ${theme.color.warning.chipText};
119
+ fill: ${theme.color.warning.chipText};
120
+ background: ${theme.color.warning.background};
121
+
122
+ &:hover {
123
+ background: ${theme.color.warning.backgroundHover};
124
+ }
125
+ `,
126
+ error: css`
127
+ color: ${theme.color.danger.chipText};
128
+ fill: ${theme.color.danger.chipText};
129
+ background: ${theme.color.danger.background};
130
+
131
+ &:hover {
132
+ background: ${theme.color.danger.backgroundHover};
133
+ }
134
+ `,
135
+ } satisfies Record<TagVariant, FlattenSimpleInterpolation>;
136
+
137
+ type StyledTagProps = WithTransientProps<
138
+ Required<Pick<TagProps<TagNodeType>, 'size' | 'variant'>>
139
+ >;
140
+
141
+ const StyledTag = styled(Box)<StyledTagProps>`
142
+ ${({ $size }) => tagSizeStyle[$size]};
143
+ ${({ $variant }) => tagVariantStyle[$variant]};
144
+
145
+ /* Static styles */
146
+ width: fit-content;
147
+ border: none;
148
+ outline: none;
149
+ display: flex;
150
+ flex-direction: row;
151
+ justify-content: center;
152
+ align-items: center;
153
+ white-space: nowrap;
154
+ gap: ${theme.space.space4};
155
+ cursor: pointer;
156
+ transition: background ${theme.transition.fastEaseOut};
157
+ `;
158
+
159
+ /**
160
+ * Component for displaying inherenly interactive chip descendant
161
+ */
162
+ function TagWrapper<T extends TagNodeType>({
163
+ as,
164
+ size = 'small',
165
+ type = 'body',
166
+ variant = 'primary',
167
+ LeadingIcon,
168
+ TrailingIcon,
169
+ children,
170
+ ...props
171
+ }: TagProps<T>,
172
+ ref: ForwardedRef<TagNodePropsMap[T]['element']>,
173
+ ) {
174
+ const component: React.ElementType = (as === 'a' ? Link : as ?? 'button');
175
+
176
+ return (
177
+ <StyledTag
178
+ as={component}
179
+ ref={ref}
180
+ $variant={variant}
181
+ $size={size}
182
+ {...props}
183
+ >
184
+ {LeadingIcon && <LeadingIcon size={TAG_ICON_SIZES[size]} />}
185
+ {children && (<Text size={size} type={type} weight="medium">{children}</Text>)}
186
+ {TrailingIcon && <TrailingIcon size={TAG_ICON_SIZES[size]} />}
187
+ </StyledTag>
188
+ );
189
+ }
190
+ TagWrapper.displayName = 'Tag';
191
+
192
+ // `forwardRef` can't handle generic types, should be fixable with React 19
193
+ export const Tag = forwardRef(TagWrapper) as <T extends TagNodeType>(
194
+ // eslint-disable-next-line no-use-before-define -- see comment above 👆
195
+ props: TagProps<T> & { ref?: ForwardedRef<TagNodePropsMap[T]['element']> },
196
+ ) => ReturnType<typeof TagWrapper>;
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import styled, { css } from 'styled-components';
3
+
4
+ import { theme } from '../../design_system/theme.js';
5
+ import type { WithTransientProps } from '../../type_utils.js';
6
+ import type { TextBaseProps } from './text_base.js';
7
+ import { TextBaseComponent } from './text_base.js';
8
+
9
+ type HeadingContentType = 'heading1' | 'heading2' | 'heading3' | 'heading4' | 'heading5' | 'heading6';
10
+
11
+ interface HeadingContentTransientProps {
12
+ type?: HeadingContentType,
13
+ }
14
+
15
+ const getContentHeadingStyles = (headingType: HeadingContentType) => css`
16
+ ${theme.typography.content.mobile[headingType]}
17
+
18
+ @media (min-width: ${theme.layout.tablet}) {
19
+ ${theme.typography.content.tablet[headingType]}
20
+ }
21
+
22
+ @media (min-width: ${theme.layout.desktop}) {
23
+ ${theme.typography.content.desktop[headingType]}
24
+ }
25
+ `;
26
+
27
+ type StyledHeadingContentProps = WithTransientProps<HeadingContentTransientProps>;
28
+ export type HeadingContentProps = HeadingContentTransientProps & TextBaseProps;
29
+
30
+ const HEADING_CONTENT_DEFAULT_ELEMENTS = {
31
+ heading1: 'h1',
32
+ heading2: 'h2',
33
+ heading3: 'h3',
34
+ heading4: 'h4',
35
+ heading5: 'h5',
36
+ heading6: 'h6',
37
+ } as const;
38
+
39
+ const StyledHeadingContent = styled(TextBaseComponent)<StyledHeadingContentProps>`
40
+ ${(props) => getContentHeadingStyles(props.$type || 'heading1')}
41
+ `;
42
+
43
+ export const HeadingContent: React.FC<HeadingContentProps> = ({
44
+ type,
45
+ as,
46
+ ...rest
47
+ }) => {
48
+ return (
49
+ <StyledHeadingContent
50
+ $type={type}
51
+ forwardedAs={as || HEADING_CONTENT_DEFAULT_ELEMENTS[type || 'heading1']}
52
+ m='none'
53
+ {...rest}
54
+ />
55
+ );
56
+ };
@@ -0,0 +1,55 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import { theme } from '../../design_system/theme.js';
5
+ import type { WithTransientProps } from '../../type_utils.js';
6
+ import type { TextBaseProps } from './text_base.js';
7
+ import { TextBaseComponent } from './text_base.js';
8
+
9
+ type HeadingMarketingType = 'titleXs' | 'titleS' | 'titleM' | 'titleL' | 'titleXl' | 'title2xl' | 'title3xl';
10
+
11
+ interface HeadingMarketingTransientProps {
12
+ type?: HeadingMarketingType,
13
+ }
14
+
15
+ type StyledHeadingMarketingProps = WithTransientProps<HeadingMarketingTransientProps>;
16
+ export type HeadingMarketingProps = HeadingMarketingTransientProps & TextBaseProps;
17
+
18
+ const HEADING_MARKETING_DEFAULT_ELEMENTS: { [Type in HeadingMarketingType]: string } = {
19
+ titleXs: 'h6',
20
+ titleS: 'h5',
21
+ titleM: 'h4',
22
+ titleL: 'h3',
23
+ titleXl: 'h2',
24
+ title2xl: 'h1',
25
+ title3xl: 'h1',
26
+ };
27
+
28
+ const StyledHeadingMarketing = styled(TextBaseComponent)<StyledHeadingMarketingProps>`
29
+ ${(props) => `
30
+ ${theme.typography.marketing.mobile[props.$type || 'titleL']}
31
+
32
+ @media (${theme.device.tablet}) {
33
+ ${theme.typography.marketing.tablet[props.$type || 'titleL']}
34
+ }
35
+
36
+ @media (${theme.device.desktop}) {
37
+ ${theme.typography.marketing.desktop[props.$type || 'titleL']}
38
+ }
39
+ `}
40
+ `;
41
+
42
+ export const HeadingMarketing: React.FC<HeadingMarketingProps> = ({
43
+ type,
44
+ as,
45
+ ...rest
46
+ }) => {
47
+ return (
48
+ <StyledHeadingMarketing
49
+ $type={type}
50
+ forwardedAs={as || HEADING_MARKETING_DEFAULT_ELEMENTS[type || 'titleL']}
51
+ m='none'
52
+ {...rest}
53
+ />
54
+ );
55
+ };