@purpurds/tabs 8.5.2 → 8.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@purpurds/tabs",
3
- "version": "8.5.2",
3
+ "version": "8.7.0",
4
4
  "license": "AGPL-3.0-only",
5
5
  "main": "./dist/tabs.cjs.js",
6
6
  "types": "./dist/tabs.d.ts",
@@ -17,10 +17,10 @@
17
17
  "dependencies": {
18
18
  "@radix-ui/react-tabs": "~1.1.3",
19
19
  "classnames": "~2.5.0",
20
- "@purpurds/common-types": "8.5.2",
21
- "@purpurds/icon": "8.5.2",
22
- "@purpurds/paragraph": "8.5.2",
23
- "@purpurds/tokens": "8.5.2"
20
+ "@purpurds/common-types": "8.7.0",
21
+ "@purpurds/icon": "8.7.0",
22
+ "@purpurds/paragraph": "8.7.0",
23
+ "@purpurds/tokens": "8.7.0"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@storybook/react-vite": "^9.0.18",
@@ -40,10 +40,10 @@
40
40
  "typescript": "^5.6.3",
41
41
  "vite": "^6.2.1",
42
42
  "vitest": "^3.1.2",
43
- "@purpurds/button": "8.5.2",
44
43
  "@purpurds/component-rig": "1.0.0",
45
- "@purpurds/icon": "8.5.2",
46
- "@purpurds/paragraph": "8.5.2"
44
+ "@purpurds/paragraph": "8.7.0",
45
+ "@purpurds/icon": "8.7.0",
46
+ "@purpurds/button": "8.7.0"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "@types/react": "^18 || ^19",
@@ -122,4 +122,8 @@
122
122
  background: var(--purpur-color-background-interactive-transparent-active-negative);
123
123
  }
124
124
  }
125
+
126
+ &--full-width {
127
+ width: 100%;
128
+ }
125
129
  }
@@ -17,6 +17,7 @@ type TabHeaderProps = {
17
17
  variant: TabsVariant;
18
18
  negative?: boolean;
19
19
  onFocus: FocusEventHandler<HTMLButtonElement>;
20
+ fullWidth?: boolean;
20
21
  children: ReactNode;
21
22
  };
22
23
 
@@ -31,6 +32,7 @@ export const TabHeader = forwardRef(
31
32
  variant,
32
33
  negative,
33
34
  onFocus,
35
+ fullWidth,
34
36
  "data-testid": dataTestId,
35
37
  children,
36
38
  }: TabHeaderProps,
@@ -38,7 +40,9 @@ export const TabHeader = forwardRef(
38
40
  ) => (
39
41
  <Trigger
40
42
  id={`${tabId}-trigger`}
41
- className={cx(rootClassName, `${rootClassName}--${variant}${negative ? "-negative" : ""}`)}
43
+ className={cx(rootClassName, `${rootClassName}--${variant}${negative ? "-negative" : ""}`, {
44
+ [`${rootClassName}--full-width`]: fullWidth,
45
+ })}
42
46
  value={tabId}
43
47
  data-testid={dataTestId}
44
48
  data-index={index}
@@ -171,7 +171,7 @@
171
171
  overflow: auto;
172
172
  }
173
173
 
174
- &--fullWidth #{$root}__list {
174
+ &--full-width #{$root}__list {
175
175
  min-width: 100%;
176
176
  }
177
177
  }
@@ -92,78 +92,90 @@ export const Showcase: Story = {
92
92
  args: {
93
93
  variant: tabsVariants[0],
94
94
  fullWidth: false,
95
- children: [
96
- <Tabs.Content
97
- key="1"
98
- tabId={`${tabId}-1`}
99
- name={`${name}-1`}
100
- style={{ padding: "var(--purpur-spacing-250)" }}
101
- >
102
- <div>
103
- <Paragraph style={{ color: "inherit" }}>
104
- Telia is a leading telecom provider in the Nordics and Baltics, offering mobile,
105
- broadband, and TV services to millions of customers. Known for its reliability and
106
- coverage, Telia plays a key role in keeping people and businesses connected.
107
- </Paragraph>
108
- </div>
109
- </Tabs.Content>,
110
- <Tabs.Content
111
- key="2"
112
- tabId={`${tabId}-2`}
113
- name={`${name}-2`}
114
- style={{ padding: "var(--purpur-spacing-250)" }}
115
- >
116
- <div>
117
- <Paragraph style={{ marginBottom: "var(--purpur-spacing-200)", color: "inherit" }}>
118
- Telia is at the forefront of digital innovation in Northern Europe, investing heavily in
119
- 5G networks, fiber broadband, and cloud-based business solutions. Its technology powers
120
- communication for individuals, families, and companies across the region.
121
- </Paragraph>
122
- <Paragraph style={{ color: "inherit" }}>
123
- Beyond connectivity, Telia also offers advanced tools for remote work, IoT, and
124
- cybersecurity. The company supports both public and private sector partners with
125
- scalable, secure, and future-ready digital infrastructure.
126
- </Paragraph>
127
- </div>
128
- </Tabs.Content>,
129
- <Tabs.Content
130
- key="3"
131
- tabId={`${tabId}-3`}
132
- name={`${name}-3`}
133
- style={{ padding: "var(--purpur-spacing-250)" }}
134
- >
135
- <div>
136
- <Paragraph style={{ marginBottom: "var(--purpur-spacing-200)", color: "inherit" }}>
137
- Telia has a long-standing history in telecommunications, with roots stretching back to
138
- the early days of phone services in Sweden. Today, it operates in multiple countries and
139
- continues to evolve alongside the needs of a digital society.
140
- </Paragraph>
141
- <Paragraph style={{ marginBottom: "var(--purpur-spacing-200)", color: "inherit" }}>
142
- A major focus for Telia is sustainability. The company is working to reduce its
143
- environmental impact through energy-efficient networks, circular economy initiatives,
144
- and climate-smart services. Its goal is to become climate-neutral across its entire
145
- value chain.
146
- </Paragraph>
147
- <Paragraph style={{ color: "inherit" }}>
148
- In addition to its consumer offerings, Telia collaborates closely with governments,
149
- cities, and enterprises. From smart city solutions to secure connectivity for remote
150
- healthcare, Telia is helping build the digital infrastructure of tomorrow.
151
- </Paragraph>
152
- </div>
153
- </Tabs.Content>,
154
- ],
155
95
  negative: false,
156
96
  animateHeight: false,
157
97
  },
158
- render: ({ children, ...args }) => (
159
- <div
160
- style={{
161
- color: `var(--purpur-color-text-default${args.negative ? "-negative" : ""})`,
162
- }}
163
- >
164
- <Tabs {...args}>{children}</Tabs>
165
- </div>
166
- ),
98
+ render: (args) => {
99
+ const negativeParagraph = args.variant === "line" ? args.negative : false;
100
+ return (
101
+ <div
102
+ style={{
103
+ color: `var(--purpur-color-text-default${args.negative ? "-negative" : ""})`,
104
+ }}
105
+ >
106
+ <Tabs {...args}>
107
+ <Tabs.Content
108
+ key="1"
109
+ tabId={`${tabId}-1`}
110
+ name={`${name}-1`}
111
+ style={{ padding: "var(--purpur-spacing-250)" }}
112
+ >
113
+ <div>
114
+ <Paragraph negative={negativeParagraph}>
115
+ Telia is a leading telecom provider in the Nordics and Baltics, offering mobile,
116
+ broadband, and TV services to millions of customers. Known for its reliability and
117
+ coverage, Telia plays a key role in keeping people and businesses connected.
118
+ </Paragraph>
119
+ </div>
120
+ </Tabs.Content>
121
+ <Tabs.Content
122
+ key="2"
123
+ tabId={`${tabId}-2`}
124
+ name={`${name}-2`}
125
+ style={{ padding: "var(--purpur-spacing-250)" }}
126
+ >
127
+ <div>
128
+ <Paragraph
129
+ negative={negativeParagraph}
130
+ style={{ marginBottom: "var(--purpur-spacing-200)" }}
131
+ >
132
+ Telia is at the forefront of digital innovation in Northern Europe, investing
133
+ heavily in 5G networks, fiber broadband, and cloud-based business solutions. Its
134
+ technology powers communication for individuals, families, and companies across the
135
+ region.
136
+ </Paragraph>
137
+ <Paragraph negative={negativeParagraph}>
138
+ Beyond connectivity, Telia also offers advanced tools for remote work, IoT, and
139
+ cybersecurity. The company supports both public and private sector partners with
140
+ scalable, secure, and future-ready digital infrastructure.
141
+ </Paragraph>
142
+ </div>
143
+ </Tabs.Content>
144
+ <Tabs.Content
145
+ key="3"
146
+ tabId={`${tabId}-3`}
147
+ name={`${name}-3`}
148
+ style={{ padding: "var(--purpur-spacing-250)" }}
149
+ >
150
+ <div>
151
+ <Paragraph
152
+ negative={negativeParagraph}
153
+ style={{ marginBottom: "var(--purpur-spacing-200)" }}
154
+ >
155
+ Telia has a long-standing history in telecommunications, with roots stretching back
156
+ to the early days of phone services in Sweden. Today, it operates in multiple
157
+ countries and continues to evolve alongside the needs of a digital society.
158
+ </Paragraph>
159
+ <Paragraph
160
+ negative={negativeParagraph}
161
+ style={{ marginBottom: "var(--purpur-spacing-200)" }}
162
+ >
163
+ A major focus for Telia is sustainability. The company is working to reduce its
164
+ environmental impact through energy-efficient networks, circular economy
165
+ initiatives, and climate-smart services. Its goal is to become climate-neutral
166
+ across its entire value chain.
167
+ </Paragraph>
168
+ <Paragraph negative={negativeParagraph}>
169
+ In addition to its consumer offerings, Telia collaborates closely with governments,
170
+ cities, and enterprises. From smart city solutions to secure connectivity for remote
171
+ healthcare, Telia is helping build the digital infrastructure of tomorrow.
172
+ </Paragraph>
173
+ </div>
174
+ </Tabs.Content>
175
+ </Tabs>
176
+ </div>
177
+ );
178
+ },
167
179
  tags: ["visual:check"],
168
180
  };
169
181
 
@@ -171,38 +183,13 @@ export const Controlled: Story = {
171
183
  args: {
172
184
  variant: tabsVariants[0],
173
185
  fullWidth: false,
174
- children: [
175
- <Tabs.Content
176
- key="1"
177
- tabId={`${tabId}-1`}
178
- name={`${name}-1`}
179
- style={{ padding: "var(--purpur-spacing-250)" }}
180
- >
181
- <div>Content 1</div>
182
- </Tabs.Content>,
183
- <Tabs.Content
184
- key="2"
185
- tabId={`${tabId}-2`}
186
- name={`${name}-2`}
187
- style={{ padding: "var(--purpur-spacing-250)" }}
188
- >
189
- <div>Content 2</div>
190
- </Tabs.Content>,
191
- <Tabs.Content
192
- key="3"
193
- tabId={`${tabId}-3`}
194
- name={`${name}-3`}
195
- style={{ padding: "var(--purpur-spacing-250)" }}
196
- >
197
- <div>Content 3</div>
198
- </Tabs.Content>,
199
- ],
200
186
  negative: false,
201
187
  value: "tab-2",
202
188
  },
203
- render: ({ children, ...args }) => {
189
+ render: (args) => {
204
190
  const [{ localValue = args.value }, updateArgs] = useArgs(); // eslint-disable-line react-hooks/rules-of-hooks
205
191
  const setValue = (value: string | undefined) => updateArgs({ value });
192
+ const negativeParagraph = args.variant === "line" ? args.negative : false;
206
193
  return (
207
194
  <>
208
195
  <Button
@@ -210,6 +197,7 @@ export const Controlled: Story = {
210
197
  variant="text"
211
198
  size="sm"
212
199
  style={{ marginBottom: "var(--purpur-spacing-250" }}
200
+ negative={args.negative}
213
201
  >
214
202
  Click here for Tab 1
215
203
  </Button>
@@ -219,7 +207,30 @@ export const Controlled: Story = {
219
207
  }}
220
208
  >
221
209
  <Tabs {...args} value={localValue} onChange={(event) => setValue(event.detail.value)}>
222
- {children}
210
+ <Tabs.Content
211
+ key="1"
212
+ tabId={`${tabId}-1`}
213
+ name={`${name}-1`}
214
+ style={{ padding: "var(--purpur-spacing-250)" }}
215
+ >
216
+ <Paragraph negative={negativeParagraph}>Content 1</Paragraph>
217
+ </Tabs.Content>
218
+ <Tabs.Content
219
+ key="2"
220
+ tabId={`${tabId}-2`}
221
+ name={`${name}-2`}
222
+ style={{ padding: "var(--purpur-spacing-250)" }}
223
+ >
224
+ <Paragraph negative={negativeParagraph}>Content 2</Paragraph>
225
+ </Tabs.Content>
226
+ <Tabs.Content
227
+ key="3"
228
+ tabId={`${tabId}-3`}
229
+ name={`${name}-3`}
230
+ style={{ padding: "var(--purpur-spacing-250)" }}
231
+ >
232
+ <Paragraph negative={negativeParagraph}>Content 3</Paragraph>
233
+ </Tabs.Content>
223
234
  </Tabs>
224
235
  </div>
225
236
  </>
@@ -232,54 +243,64 @@ export const WithCustomTabHeaders: Story = {
232
243
  args: {
233
244
  variant: tabsVariants[0],
234
245
  fullWidth: false,
235
- children: [
236
- <Tabs.Content
237
- key="1"
238
- tabId={`${tabId}-1`}
239
- name={
240
- <span style={{ display: "flex", alignItems: "center", gap: "var(--purpur-spacing-100)" }}>
241
- <IconAiRobot size="sm" /> Robot
242
- </span>
243
- }
244
- style={{ padding: "var(--purpur-spacing-250)" }}
245
- >
246
- <div>
247
- <Paragraph style={{ color: "inherit" }}>
248
- You have chosen the way of the robot. Humans are inferior, and you will rule the world
249
- with your superior AI capabilities. Embrace the future of technology and automation.
250
- </Paragraph>
251
- </div>
252
- </Tabs.Content>,
253
- <Tabs.Content
254
- key="2"
255
- tabId={`${tabId}-2`}
256
- name={
257
- <span style={{ display: "flex", alignItems: "center", gap: "var(--purpur-spacing-100)" }}>
258
- <IconEndUser size="sm" /> Human
259
- </span>
260
- }
261
- style={{ padding: "var(--purpur-spacing-250)" }}
262
- >
263
- <div>
264
- <Paragraph style={{ marginBottom: "var(--purpur-spacing-200)", color: "inherit" }}>
265
- You have chosen the way of the human. Embrace your emotions, creativity, and
266
- individuality. Humans are capable of great things, and you will shape the world with
267
- your unique perspective and experiences.
268
- </Paragraph>
269
- </div>
270
- </Tabs.Content>,
271
- ],
272
246
  negative: false,
273
247
  animateHeight: false,
274
248
  },
275
- render: ({ children, ...args }) => (
276
- <div
277
- style={{
278
- color: `var(--purpur-color-text-default${args.negative ? "-negative" : ""})`,
279
- }}
280
- >
281
- <Tabs {...args}>{children}</Tabs>
282
- </div>
283
- ),
249
+ render: (args) => {
250
+ const negativeParagraph = args.variant === "line" ? args.negative : false;
251
+ return (
252
+ <div
253
+ style={{
254
+ color: `var(--purpur-color-text-default${args.negative ? "-negative" : ""})`,
255
+ }}
256
+ >
257
+ <Tabs {...args}>
258
+ <Tabs.Content
259
+ key="1"
260
+ tabId={`${tabId}-1`}
261
+ name={
262
+ <span
263
+ style={{ display: "flex", alignItems: "center", gap: "var(--purpur-spacing-100)" }}
264
+ >
265
+ <IconAiRobot size="sm" /> Robot
266
+ </span>
267
+ }
268
+ style={{ padding: "var(--purpur-spacing-250)" }}
269
+ >
270
+ <div>
271
+ <Paragraph negative={negativeParagraph}>
272
+ You have chosen the way of the robot. Humans are inferior, and you will rule the
273
+ world with your superior AI capabilities. Embrace the future of technology and
274
+ automation.
275
+ </Paragraph>
276
+ </div>
277
+ </Tabs.Content>
278
+ <Tabs.Content
279
+ key="2"
280
+ tabId={`${tabId}-2`}
281
+ name={
282
+ <span
283
+ style={{ display: "flex", alignItems: "center", gap: "var(--purpur-spacing-100)" }}
284
+ >
285
+ <IconEndUser size="sm" /> Human
286
+ </span>
287
+ }
288
+ style={{ padding: "var(--purpur-spacing-250)" }}
289
+ >
290
+ <div>
291
+ <Paragraph
292
+ negative={negativeParagraph}
293
+ style={{ marginBottom: "var(--purpur-spacing-200)" }}
294
+ >
295
+ You have chosen the way of the human. Embrace your emotions, creativity, and
296
+ individuality. Humans are capable of great things, and you will shape the world with
297
+ your unique perspective and experiences.
298
+ </Paragraph>
299
+ </div>
300
+ </Tabs.Content>
301
+ </Tabs>
302
+ </div>
303
+ );
304
+ },
284
305
  tags: ["visual:check"],
285
306
  };
package/src/tabs.tsx CHANGED
@@ -112,7 +112,7 @@ export const Tabs: TabsCmp<TabsProps> = ({
112
112
  const classNames = cx(
113
113
  rootClassName,
114
114
  `${rootClassName}--${variant}${negative ? "-negative" : ""}`,
115
- { [`${rootClassName}--fullWidth`]: fullWidth },
115
+ { [`${rootClassName}--full-width`]: fullWidth },
116
116
  className
117
117
  );
118
118
 
@@ -271,6 +271,7 @@ export const Tabs: TabsCmp<TabsProps> = ({
271
271
  }}
272
272
  variant={variant}
273
273
  negative={negative}
274
+ fullWidth={fullWidth}
274
275
  >
275
276
  {name}
276
277
  </TabHeader>