Skip to content

Commit e0c942e

Browse files
feat(box): DLT-3315 new DtBox primitive component (#1203)
1 parent 61bb610 commit e0c942e

46 files changed

Lines changed: 2851 additions & 633 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/dialtone-documentation/docs/.vuepress/baseComponents/ComponentHealthStatusTable.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<dt-stack gap="200" direction="row" class="d-bgc-secondary d-p-200 d-py-100 d-bar8 d-ba d-bc-subtle d-my-200">
33
<dt-stack direction="row" gap="100">
44
<dt-icon
5-
class="d-fc-success"
5+
class="d-fc-positive"
66
name="check-circle"
77
size="300"
88
/>
@@ -114,7 +114,7 @@ const statusIcon = {
114114
'N/A': 'box',
115115
};
116116
const statusColor = {
117-
Ready: 'd-fc-success',
117+
Ready: 'd-fc-positive',
118118
'In progress': 'd-fc-warning',
119119
Planned: 'd-fc-critical',
120120
'N/A': 'd-fc-muted',

apps/dialtone-documentation/docs/.vuepress/baseComponents/CopyButton.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<dt-icon
1111
:name="copied ? 'check' : 'copy'"
1212
:size="iconSize"
13-
:class="{ 'd-fc-success': copied }"
13+
:class="{ 'd-fc-positive': copied }"
1414
/>
1515
</template>
1616
<template v-if="copied">

apps/dialtone-documentation/docs/.vuepress/exampleComponents/ExampleProfileCard.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
Katie Rodriguez
77
</dt-text>
88
<dt-stack direction="row" gap="75">
9-
<dt-text tone="success">
9+
<dt-text tone="positive">
1010
Available
1111
</dt-text>
1212
<dt-text>&bull;</dt-text>

apps/dialtone-documentation/docs/.vuepress/public/assets/images/chart-dondont-1-1.svg

Lines changed: 2 additions & 2 deletions
Loading

apps/dialtone-documentation/docs/.vuepress/public/assets/images/chart-dondont-1-2.svg

Lines changed: 2 additions & 2 deletions
Loading

apps/dialtone-documentation/docs/.vuepress/public/assets/images/chart-dondont-4-1.svg

Lines changed: 2 additions & 2 deletions
Loading

apps/dialtone-documentation/docs/.vuepress/public/assets/images/chart-dondont-4-2.svg

Lines changed: 2 additions & 2 deletions
Loading

apps/dialtone-documentation/docs/.vuepress/theme/components/PageHeader.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
<dt-icon
7676
:name="showCopiedIcon ? 'check' : 'copy'"
7777
:size="size"
78-
:class="{ 'd-fc-success': showCopiedIcon }"
78+
:class="{ 'd-fc-positive': showCopiedIcon }"
7979
/>
8080
</template>
8181
Copy MD

apps/dialtone-documentation/docs/_data/site-nav.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@
253253
"text": "Banner",
254254
"link": "/components/banner.html"
255255
},
256+
{
257+
"text": "Box",
258+
"link": "/components/box.html"
259+
},
256260
{
257261
"text": "Breadcrumbs",
258262
"link": "/components/breadcrumbs.html"
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
---
2+
title: Box
3+
description: Low-level surface and spacing primitive for building token-constrained containers.
4+
status: beta
5+
thumb: true
6+
storybook: https://dialtone.dialpad.com/vue/?path=/story/components-box--default
7+
keywords: ["box", "container", "surface", "padding", "border", "shadow", "radius", "sizing", "overflow", "scrollbar", "background", "spacing", "layout", "primitive", "elevation"]
8+
---
9+
10+
<component-combinator component-name="DtBox" />
11+
12+
## Usage
13+
14+
```vue code-only
15+
<dt-box> ... </dt-box>
16+
```
17+
18+
DtBox complements [DtText](/components/text.html) (typography) and [DtStack](/components/stack.html) (flex layout) to form Dialtone's **primitive triad**:
19+
20+
* **DtBox**: what the container *is* (`surface`, `border`, `padding`, `sizing`)
21+
* **DtText**: what the content *looks* like (`font`, `size`, `color`)
22+
* **DtStack**: how children are *arranged* (`direction`, `gap`, `alignment`)
23+
24+
### Guidance
25+
26+
* Use DtBox in place of composing multiple surface utility classes (e.g., `d-bgc-*`, `d-bc-*`, `d-bar*`, `d-bs-*`, `d-p-*`).
27+
* Use the `as` prop to render semantic HTML elements (`section`, `nav`, `article`, `header`, etc.) for accessibility.
28+
* DtBox is a **passive container** — it does not handle layout (use [DtStack](/components/stack.html)) or typography (use [DtText](/components/text.html)).
29+
* Compose DtBox + DtStack + DtText together for structured UI surface containers.
30+
31+
<dialtone-usage>
32+
<template #do>
33+
34+
* Use DtBox for card surfaces, info panels, content regions, and any container that needs surface styling.
35+
* Compose with DtStack for layout: `<dt-box><dt-stack>...</dt-stack></dt-box>`.
36+
* Use the `as` prop for semantic HTML: `<dt-box as="nav">`, `<dt-box as="section">`.
37+
* Use `class` for one-off styling outside DtBox's prop surface (e.g., `class="d-ps-sticky"`).
38+
39+
</template>
40+
<template #dont>
41+
42+
* Don't use DtBox for flex layout — use [DtStack](/components/stack.html) for direction, gap, alignment.
43+
* Don't use DtBox for typography — use [DtText](/components/text.html) for font, size, tone.
44+
* Don't use utility classes for properties DtBox already handles (e.g., avoid `class="d-bgc-primary"` when `surface="primary"` exists).
45+
* Don't nest DtBox deeply when a dedicated component (DtCard, DtNotice) better fits the pattern.
46+
47+
</template>
48+
</dialtone-usage>
49+
50+
## Surface
51+
52+
Background surface color mapped to `--dt-color-surface-*` tokens.
53+
54+
```vue demo
55+
<!-- @wrapper -->
56+
<dt-stack direction="row" gap="200">
57+
<dt-box padding="200" surface="primary" border-width="100" border-radius="300">primary</dt-box>
58+
<dt-box padding="200" surface="secondary" border-width="100" border-radius="300">secondary</dt-box>
59+
<dt-box padding="200" surface="moderate" border-width="100" border-radius="300">moderate</dt-box>
60+
<dt-box padding="200" surface="bold" border-width="100" border-radius="300">bold</dt-box>
61+
<dt-box padding="200" surface="strong" border-width="100" border-radius="300">strong</dt-box>
62+
</dt-stack>
63+
<!-- @code -->
64+
<dt-box surface="{surfaceColor}">...</dt-box>
65+
```
66+
67+
### Semantic surfaces
68+
69+
```vue demo
70+
<!-- @wrapper -->
71+
<dt-stack direction="row" gap="200">
72+
<dt-box padding="200" surface="brand" border-width="100" border-radius="300">brand</dt-box>
73+
<dt-box padding="200" surface="info" border-width="100" border-radius="300">info</dt-box>
74+
<dt-box padding="200" surface="positive" border-width="100" border-radius="300">positive</dt-box>
75+
<dt-box padding="200" surface="warning" border-width="100" border-radius="300">warning</dt-box>
76+
<dt-box padding="200" surface="critical" border-width="100" border-radius="300">critical</dt-box>
77+
</dt-stack>
78+
<!-- @code -->
79+
<dt-box surface="{surfaceColor}">...</dt-box>
80+
```
81+
82+
## Padding
83+
84+
Spacing token scale values for internal whitespace. The padding cascade resolves specific sides over axis shorthands over the all-sides shorthand.
85+
86+
```vue demo
87+
<!-- @wrapper -->
88+
<dt-stack direction="row" gap="200">
89+
<dt-box padding="200" surface="moderate" border-radius="300">padding="200"</dt-box>
90+
<dt-box padding="300" surface="moderate" border-radius="300">padding="300"</dt-box>
91+
<dt-box padding="400" surface="moderate" border-radius="300">padding="400"</dt-box>
92+
</dt-stack>
93+
<!-- @code -->
94+
<dt-box padding="{padding}">...</dt-box>
95+
```
96+
97+
### Directional padding
98+
99+
Override specific sides. The cascade resolves: `paddingBlockStart` > `paddingBlock` > `padding`.
100+
101+
```vue demo
102+
<!-- @wrapper -->
103+
<dt-stack gap="200">
104+
<dt-box padding="200" surface="moderate" border-radius="300">All sides: 200</dt-box>
105+
<dt-box padding="200" padding-inline="400" surface="moderate" border-radius="300">Inline override: 400</dt-box>
106+
<dt-box padding="200" padding-block-start="400" surface="moderate" border-radius="300">Block-start override: 400</dt-box>
107+
</dt-stack>
108+
```
109+
110+
## Border
111+
112+
### Border width
113+
114+
No visible border until a `border-width` is set. Uniform width applies to all sides.
115+
116+
```vue demo
117+
<!-- @wrapper -->
118+
<dt-stack direction="row" gap="200">
119+
<dt-box padding="200" surface="moderate" border-radius="300">No border</dt-box>
120+
<dt-box padding="200" surface="moderate" border-width="100" border-radius="300">100</dt-box>
121+
<dt-box padding="200" surface="moderate" border-width="200" border-radius="300">200</dt-box>
122+
</dt-stack>
123+
```
124+
125+
### Directional border width
126+
127+
Show borders on specific sides only.
128+
129+
```vue demo
130+
<!-- @wrapper -->
131+
<dt-stack direction="row" gap="200">
132+
<dt-box padding="200" surface="moderate" border-width-block-end="100">Bottom only</dt-box>
133+
<dt-box padding="200" surface="moderate" border-width-inline-start="200" border-color="critical">Start critical</dt-box>
134+
<dt-box padding="200" surface="moderate" border-width-block="100" border-width-inline="0">Block only</dt-box>
135+
</dt-stack>
136+
```
137+
138+
### Border color
139+
140+
Defaults to `'default'` (`--dt-color-border-default`). Only visible when a `border-width` is set.
141+
142+
```vue demo
143+
<!-- @wrapper -->
144+
<dt-stack direction="row" gap="200">
145+
<dt-box padding="200" surface="moderate" border-width="100" border-radius="300">default</dt-box>
146+
<dt-box padding="200" surface="moderate" border-width="100" border-color="subtle" border-radius="300">subtle</dt-box>
147+
<dt-box padding="200" surface="moderate" border-width="100" border-color="critical" border-radius="300">critical</dt-box>
148+
<dt-box padding="200" surface="moderate" border-width="100" border-color="positive" border-radius="300">positive</dt-box>
149+
</dt-stack>
150+
```
151+
152+
### Border radius
153+
154+
```vue demo
155+
<!-- @wrapper -->
156+
<dt-stack direction="row" gap="200" align="center">
157+
<dt-box padding="200" surface="moderate" border-radius="0">0</dt-box>
158+
<dt-box padding="200" surface="moderate" border-radius="200">200</dt-box>
159+
<dt-box padding="200" surface="moderate" border-radius="400">400</dt-box>
160+
<dt-box padding="200" surface="moderate" border-radius="pill" inline-size="200" class="d-ta-center">pill</dt-box>
161+
<dt-box surface="moderate" border-radius="circle" inline-size="100" block-size="100" class="d-plc-center d-ta-center">circle</dt-box>
162+
</dt-stack>
163+
```
164+
165+
## Shadow
166+
167+
```vue demo
168+
<!-- @wrapper -->
169+
<dt-stack direction="row" gap="300">
170+
<dt-box padding="200" surface="moderate" border-radius="300" shadow="small">small</dt-box>
171+
<dt-box padding="200" surface="moderate" border-radius="300" shadow="medium">medium</dt-box>
172+
<dt-box padding="200" surface="moderate" border-radius="300" shadow="large">large</dt-box>
173+
<dt-box padding="200" surface="moderate" border-radius="300" shadow="card">card</dt-box>
174+
</dt-stack>
175+
```
176+
177+
## Sizing
178+
179+
Maps to Dialtone's **layout token scale** (`--dt-layout-*`). Supports both fixed values and percentage tokens.
180+
181+
```vue demo
182+
<!-- @wrapper -->
183+
<dt-stack direction="row" gap="200">
184+
<dt-box padding="200" surface="moderate" border-radius="300" inline-size="300">300 (192px)</dt-box>
185+
<dt-box padding="200" surface="moderate" border-radius="300" inline-size="500">500 (320px)</dt-box>
186+
<dt-box padding="200" surface="moderate" border-radius="300" inline-size="50-percent">50-percent</dt-box>
187+
</dt-stack>
188+
```
189+
190+
## Overflow
191+
192+
```vue demo
193+
<dt-box
194+
surface="moderate"
195+
border-radius="300"
196+
overflow="hidden"
197+
inline-size="500"
198+
block-size="200"
199+
padding="200"
200+
>
201+
Tall content clipped by <dt-text kind="code" size="200">overflow="hidden"</dt-text>. Nemo rem ullam culpa ut laudantium repellat unde. Consequuntur cupiditate voluptatem velit rerum doloremque voluptatum commodi vitae vel inventore iusto ducimus iure? Ex fugit quae iste perferendis eaque! Alias in reiciendis suscipit facere incidunt repellendus! Voluptatibus iste nesciunt numquam consectetur suscipit unde atque tempora saepe est illum quaerat sit natus mollitia excepturi? Repellendus explicabo deserunt ipsam sint esse ab delectus beatae eligendi velit libero quasi culpa ut tenetur sunt corrupti iure suscipit magni fuga blanditiis nihil incidunt! Mollitia voluptas sed temporibus quasi.
202+
</dt-box>
203+
```
204+
205+
## Scrollbar
206+
207+
Integrates the `v-dt-scrollbar` directive. An inner viewport wrapper is inserted automatically, solving the [Custom Scrollbar's](/components/scrollbar.html) single-child constraint.
208+
209+
```vue demo
210+
<dt-box
211+
padding="200"
212+
border-width="100"
213+
border-radius="300"
214+
scrollbar="never"
215+
block-size="300"
216+
>
217+
<dt-stack gap="100">
218+
<dt-text v-for="i in 20" :key="i" kind="body" size="sm">Scrollable item {{ i }}</dt-text>
219+
</dt-stack>
220+
</dt-box>
221+
```
222+
223+
## Render as
224+
225+
Use the `as` prop to render semantic HTML elements for accessibility.
226+
227+
```vue demo
228+
<!-- @wrapper -->
229+
<dt-stack gap="200">
230+
<dt-box as="section" padding="200" surface="moderate" border-radius="300">as="section"</dt-box>
231+
<dt-box as="nav" padding="200" surface="moderate" border-radius="300">as="nav"</dt-box>
232+
<dt-box as="article" padding="200" surface="moderate" border-radius="300">as="article"</dt-box>
233+
</dt-stack>
234+
```
235+
236+
## Examples
237+
238+
### Card
239+
240+
```vue demo
241+
<dt-box
242+
padding="300"
243+
surface="primary"
244+
border-width="100"
245+
border-radius="400"
246+
shadow="card"
247+
>
248+
<dt-stack gap="200">
249+
<dt-text as="h3" kind="headline" size="md">Card title</dt-text>
250+
<dt-text kind="body" size="sm">Card body content with supporting text.</dt-text>
251+
</dt-stack>
252+
</dt-box>
253+
```
254+
255+
### Composed layout
256+
257+
```vue demo
258+
<dt-box
259+
padding="200"
260+
surface="primary"
261+
border-width="100"
262+
border-radius="400"
263+
>
264+
<dt-stack gap="200">
265+
<dt-stack direction="row" justify="space-between" align="baseline">
266+
<dt-text as="h2" kind="headline" :size="400">Title</dt-text>
267+
<dt-button size="200">Action</dt-button>
268+
</dt-stack>
269+
<dt-stack direction="row" gap="200">
270+
<dt-box class="d-fl1" padding="200" surface="secondary" border-width="100" border-color="subtle" border-radius="300">
271+
<dt-text as="p" align="center" tone="muted">Box 1</dt-text>
272+
</dt-box>
273+
<dt-box class="d-fl1" padding="200" surface="secondary" border-width="100" border-color="subtle" border-radius="300">
274+
<dt-text as="p" align="center" tone="muted">Box 2</dt-text>
275+
</dt-box>
276+
<dt-box class="d-fl1" padding="200" surface="secondary" border-width="100" border-color="subtle" border-radius="300">
277+
<dt-text as="p" align="center" tone="muted">Box 3</dt-text>
278+
</dt-box>
279+
</dt-stack>
280+
</dt-stack>
281+
</dt-box>
282+
```
283+
284+
## Accessibility
285+
286+
* Use the `as` prop to render appropriate semantic elements — `nav` for navigation, `section` for thematic content, `article` for self-contained content.
287+
* DtBox does not add any implicit ARIA role. The rendered element's native semantics determine how screen readers interpret it.
288+
* When using `as="nav"` or `as="section"`, consider adding `aria-label` to provide an accessible name for the landmark region.
289+
* The scrollbar integration preserves native keyboard scrolling behavior.
290+
291+
## Vue API
292+
293+
<component-vue-api component-name="box" />
294+
295+
## Classes
296+
297+
<component-class-table component-name="box" />

0 commit comments

Comments
 (0)