@tribepad/themis 1.8.1 → 1.9.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": "@tribepad/themis",
3
- "version": "1.8.1",
3
+ "version": "1.9.0",
4
4
  "description": "Accessible React component library built on React Aria primitives",
5
5
  "author": "Tribepad <mbasford@tribepad.com>",
6
6
  "license": "MIT",
@@ -11,6 +11,7 @@ import { useState } from 'react';
11
11
  import type { Meta, StoryObj } from '@storybook/react-vite';
12
12
  import { Modal } from './Modal';
13
13
  import { Button } from '../Button';
14
+ import { Tabs, TabList, Tab, TabPanel } from '../Tabs';
14
15
 
15
16
  const meta = {
16
17
  title: 'Elements/Modal',
@@ -128,28 +129,30 @@ export const WithForm: Story = {
128
129
  alert('Form submitted!');
129
130
  }}
130
131
  >
131
- <div className="grid gap-4 py-4">
132
- <div className="grid grid-cols-4 items-center gap-4">
133
- <label htmlFor="name" className="text-right">
134
- Name
135
- </label>
136
- <input
137
- id="name"
138
- defaultValue="Pedro Duarte"
139
- className="col-span-3 px-3 py-2 rounded-md border border-[var(--border)] bg-[var(--background)]"
140
- />
132
+ <Modal.Body>
133
+ <div className="grid gap-4">
134
+ <div className="grid grid-cols-4 items-center gap-4">
135
+ <label htmlFor="name" className="text-right">
136
+ Name
137
+ </label>
138
+ <input
139
+ id="name"
140
+ defaultValue="Pedro Duarte"
141
+ className="col-span-3 px-3 py-2 rounded-md border border-[var(--border)] bg-[var(--background)]"
142
+ />
143
+ </div>
144
+ <div className="grid grid-cols-4 items-center gap-4">
145
+ <label htmlFor="username" className="text-right">
146
+ Username
147
+ </label>
148
+ <input
149
+ id="username"
150
+ defaultValue="@peduarte"
151
+ className="col-span-3 px-3 py-2 rounded-md border border-[var(--border)] bg-[var(--background)]"
152
+ />
153
+ </div>
141
154
  </div>
142
- <div className="grid grid-cols-4 items-center gap-4">
143
- <label htmlFor="username" className="text-right">
144
- Username
145
- </label>
146
- <input
147
- id="username"
148
- defaultValue="@peduarte"
149
- className="col-span-3 px-3 py-2 rounded-md border border-[var(--border)] bg-[var(--background)]"
150
- />
151
- </div>
152
- </div>
155
+ </Modal.Body>
153
156
  <Modal.Footer>
154
157
  <Modal.Close>
155
158
  <Button variant="outline">Cancel</Button>
@@ -162,6 +165,70 @@ export const WithForm: Story = {
162
165
  ),
163
166
  };
164
167
 
168
+ /**
169
+ * Tabbed Modal
170
+ *
171
+ * A full-width tab strip below the title switches the modal body. The React
172
+ * Aria `<Tabs>` provider wraps both the `Modal.Tabs` (tablist) and `Modal.Body`
173
+ * (panels) so selection is shared across the two regions. The `<Tabs>` element
174
+ * gets `flex min-h-0 flex-1 flex-col` so the body grows and scrolls while the
175
+ * header and tab strip stay pinned.
176
+ */
177
+ export const TabbedModal: Story = {
178
+ render: () => (
179
+ <Modal>
180
+ <Modal.Trigger>
181
+ <Button>Edit profile</Button>
182
+ </Modal.Trigger>
183
+ <Modal.Content size="lg">
184
+ <Modal.Header>
185
+ <Modal.Title>Edit profile</Modal.Title>
186
+ <Modal.Description>
187
+ Update your details across the sections below.
188
+ </Modal.Description>
189
+ </Modal.Header>
190
+ <Tabs
191
+ defaultSelectedKey="details"
192
+ className="flex min-h-0 flex-1 flex-col"
193
+ >
194
+ <Modal.Tabs>
195
+ <TabList aria-label="Profile sections">
196
+ <Tab id="details">Details</Tab>
197
+ <Tab id="activity">Activity</Tab>
198
+ <Tab id="settings">Settings</Tab>
199
+ </TabList>
200
+ </Modal.Tabs>
201
+ <Modal.Body>
202
+ <TabPanel id="details">
203
+ <p className="text-sm">
204
+ Your name, contact details, and profile photo live here.
205
+ </p>
206
+ </TabPanel>
207
+ <TabPanel id="activity">
208
+ <p className="text-sm">
209
+ A chronological feed of recent account activity.
210
+ </p>
211
+ </TabPanel>
212
+ <TabPanel id="settings">
213
+ <p className="text-sm">
214
+ Notification, privacy, and accessibility preferences.
215
+ </p>
216
+ </TabPanel>
217
+ </Modal.Body>
218
+ </Tabs>
219
+ <Modal.Footer>
220
+ <Modal.Close>
221
+ <Button variant="outline">Cancel</Button>
222
+ </Modal.Close>
223
+ <Modal.Close>
224
+ <Button>Save changes</Button>
225
+ </Modal.Close>
226
+ </Modal.Footer>
227
+ </Modal.Content>
228
+ </Modal>
229
+ ),
230
+ };
231
+
165
232
  /**
166
233
  * Long Content
167
234
  * Modal with scrolling content
@@ -180,7 +247,7 @@ export const LongContent: Story = {
180
247
  Please read and accept our terms of service to continue.
181
248
  </Modal.Description>
182
249
  </Modal.Header>
183
- <div className="max-h-[400px] overflow-y-auto pr-4">
250
+ <Modal.Body>
184
251
  <div className="space-y-4">
185
252
  <h3 className="font-semibold">1. Acceptance of Terms</h3>
186
253
  <p className="text-sm text-[var(--muted-foreground)]">
@@ -230,7 +297,7 @@ export const LongContent: Story = {
230
297
  risk.
231
298
  </p>
232
299
  </div>
233
- </div>
300
+ </Modal.Body>
234
301
  <Modal.Footer>
235
302
  <Modal.Close>
236
303
  <Button variant="outline">Decline</Button>
@@ -296,11 +363,11 @@ export const NoDescription: Story = {
296
363
  <Modal.Header>
297
364
  <Modal.Title>Quick Confirmation</Modal.Title>
298
365
  </Modal.Header>
299
- <div className="py-4">
366
+ <Modal.Body>
300
367
  <p className="text-sm">
301
368
  Are you sure you want to proceed with this action?
302
369
  </p>
303
- </div>
370
+ </Modal.Body>
304
371
  <Modal.Footer>
305
372
  <Modal.Close>
306
373
  <Button variant="outline">Cancel</Button>
@@ -337,11 +404,11 @@ export const NotDismissable: Story = {
337
404
  Escape. You must select one of the options below.
338
405
  </Modal.Description>
339
406
  </Modal.Header>
340
- <div className="py-4">
407
+ <Modal.Body>
341
408
  <p className="text-sm text-[var(--muted-foreground)]">
342
409
  Please review the terms and conditions before proceeding.
343
410
  </p>
344
- </div>
411
+ </Modal.Body>
345
412
  <Modal.Footer>
346
413
  <Modal.Close>
347
414
  <Button variant="outline">Decline</Button>
@@ -425,7 +492,7 @@ export const AllThemes: Story = {
425
492
  light, dark, high contrast, and colorblind themes.
426
493
  </Modal.Description>
427
494
  </Modal.Header>
428
- <div className="space-y-4 py-4">
495
+ <Modal.Body className="space-y-4">
429
496
  <div className="rounded-md bg-[var(--muted)] p-4">
430
497
  <p className="text-sm">
431
498
  Background: <code>var(--background)</code>
@@ -437,7 +504,7 @@ export const AllThemes: Story = {
437
504
  Border: <code>var(--border)</code>
438
505
  </p>
439
506
  </div>
440
- </div>
507
+ </Modal.Body>
441
508
  <Modal.Footer>
442
509
  <Modal.Close>
443
510
  <Button variant="outline">Close</Button>