@xzibit/ui 0.1.1 → 0.3.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/CHANGELOG.md CHANGED
@@ -2,6 +2,44 @@
2
2
 
3
3
  All notable changes to `@xzibit/ui` are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/) loosely; versioning follows [SemVer](https://semver.org/).
4
4
 
5
+ ## [0.3.0] — 2026-05-24
6
+
7
+ ### Added
8
+
9
+ - **`disablePadding` prop on `<ContentContainer>`** — when `true`, renders no padding (only `max-width` + `margin: 0 auto`). For app-shell integration where the parent layout already provides padding (e.g. left-nav offset), preventing the tier padding from stacking and reducing effective content width.
10
+
11
+ ```tsx
12
+ <ContentContainer tier="reference" disablePadding>
13
+ {/* shell-managed padding flows through */}
14
+ </ContentContainer>
15
+ ```
16
+
17
+ ### Why
18
+
19
+ ERP Overview Phase 1.13 (the canonical `<ContentContainer>` migration ship 2026-05-24) surfaced a left-nav stacking conflict: the per-page outer div uses `padding: '2.5rem 2.5rem 2.5rem 280px'` (left-nav offset), and stacking the container's `3rem 2rem` reduces effective width on wide monitors from the spec's 1200px to ~816px. Their resolution — `className="content-container--layout"` + `!important` padding zero — works but is a smell. `disablePadding` is the canonical API. Every left-nav-bearing portfolio app will hit this same conflict; this prop is the right answer for v0.3 before the portfolio-wide broadcast.
20
+
21
+ ### Backward compatible
22
+
23
+ `disablePadding` defaults to `false`. v0.2.x adopters who don't set it see no change. v0.3+ is the recommended version for app-shell integration; v0.2.x is fine for page-level adoption where shell padding isn't a concern.
24
+
25
+ ---
26
+
27
+ ## [0.2.0] — 2026-05-24
28
+
29
+ ### Added
30
+
31
+ - **`<ContentContainer tier="...">`** — implements DESIGN-STANDARD v2.4 §Content Density Tiers. Three tiers: `'editorial'` (720px), `'reference'` (1200px, DEFAULT), `'data'` (unconstrained with 32px side padding). Drop-in wrapper for `<main>` content. Per-page overrides via `tier` prop.
32
+ - **`ContentTier`** type exported for app authors wanting to type tier props at their own layer.
33
+
34
+ ### Coming next
35
+
36
+ - `<Toast />` + `useToast()` — wrapper around `sonner` per DESIGN-STANDARD §Toast / Notification (v2.2). Will ship as v0.2.1 once drafted.
37
+ - `<Modal />` — wrapper around `@radix-ui/react-dialog` per DESIGN-STANDARD §Modal / Dialog (v2.2). Will ship as v0.2.2 once drafted.
38
+
39
+ (Joel chose Option A 2026-05-24 — fast-ship v0.2.0 with just ContentContainer to unblock portfolio-wide adoption of the new content tier system. Toast + Modal ship as subsequent patches.)
40
+
41
+ ---
42
+
5
43
  ## [0.1.1] — 2026-05-24
6
44
 
7
45
  ### Fixed
package/README.md CHANGED
@@ -146,6 +146,7 @@ This sets `--xz-charcoal`, `--xz-teal`, `--xz-white`, `--border`, etc. — and `
146
146
  | `<AppsDropdown />` | Sectioned + alphabetical apps dropdown driven by `/api/me/apps` |
147
147
  | `<XzibitMark size={28} />` | Xzibit X brand mark as inline SVG (any size, any density) |
148
148
  | `useApps()` | React hook fetching `/api/me/apps` with loading + error + refetch |
149
+ | `<ContentContainer tier="reference">` *(v0.2+)* | Content max-width container per DESIGN-STANDARD v2.4 §Content Density Tiers — tiers: `'editorial'` (720px), `'reference'` (1200px, default), `'data'` (unconstrained). Wraps `<main>` content. v0.3+ adds `disablePadding` prop for app-shell integration where layout already provides padding (e.g. left-nav offset). |
149
150
 
150
151
  ---
151
152
 
package/dist/index.cjs CHANGED
@@ -22,6 +22,7 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AppsDropdown: () => AppsDropdown,
24
24
  BackToLauncher: () => BackToLauncher,
25
+ ContentContainer: () => ContentContainer,
25
26
  TopBar: () => TopBar,
26
27
  XzibitMark: () => XzibitMark,
27
28
  normalizeApp: () => normalizeApp,
@@ -559,10 +560,37 @@ function BuildBadge({
559
560
  }
560
561
  );
561
562
  }
563
+
564
+ // src/ContentContainer.tsx
565
+ var import_jsx_runtime5 = require("react/jsx-runtime");
566
+ var TIER_MAX_WIDTH = {
567
+ editorial: 720,
568
+ reference: 1200,
569
+ data: "100%"
570
+ };
571
+ var TIER_PADDING = {
572
+ editorial: "3rem 2rem",
573
+ reference: "3rem 2rem",
574
+ data: "1.5rem 2rem"
575
+ };
576
+ function ContentContainer({
577
+ tier = "reference",
578
+ disablePadding = false,
579
+ className,
580
+ children
581
+ }) {
582
+ const style = {
583
+ maxWidth: TIER_MAX_WIDTH[tier],
584
+ margin: "0 auto",
585
+ ...disablePadding ? {} : { padding: TIER_PADDING[tier] }
586
+ };
587
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className, style, children });
588
+ }
562
589
  // Annotate the CommonJS export names for ESM import in node:
563
590
  0 && (module.exports = {
564
591
  AppsDropdown,
565
592
  BackToLauncher,
593
+ ContentContainer,
566
594
  TopBar,
567
595
  XzibitMark,
568
596
  normalizeApp,
package/dist/index.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
2
3
 
3
4
  interface TopBarProps {
4
5
  /** App display name shown in the wordmark slot (e.g. "ERP Overview"). */
@@ -181,4 +182,66 @@ interface UseAppsOptions {
181
182
  */
182
183
  declare function useApps(options?: UseAppsOptions): UseAppsResult;
183
184
 
184
- export { type App, AppsDropdown, type AppsDropdownProps, type AppsResponse, BackToLauncher, type BackToLauncherProps, type RawApp, TopBar, type TopBarProps, type UseAppsOptions, type UseAppsResult, XzibitMark, type XzibitMarkProps, normalizeApp, useApps };
185
+ /**
186
+ * Content density tier per DESIGN-STANDARD v2.4 §Content Density Tiers.
187
+ *
188
+ * - `'editorial'`: 720px max-width — marketing / public-facing docs / long-form prose
189
+ * - `'reference'` (DEFAULT): 1200px max-width — internal docs / wikis / dashboards / most app pages
190
+ * - `'data'`: unconstrained with 32px min side padding — wide tables / kanban / calendars / heatmaps
191
+ */
192
+ type ContentTier = 'editorial' | 'reference' | 'data';
193
+ interface ContentContainerProps {
194
+ /**
195
+ * Content density tier — picks max-width + padding.
196
+ * Defaults to `'reference'` (the portfolio default per v2.4).
197
+ */
198
+ tier?: ContentTier;
199
+ /**
200
+ * If `true`, render no padding — useful when the parent app shell already
201
+ * provides layout-level padding (e.g. left-nav offset).
202
+ *
203
+ * Default: `false` (tier padding is applied).
204
+ *
205
+ * **Common use case:** app-shell `layout.tsx` integration where the surrounding
206
+ * layout div sets `padding: '2.5rem 2.5rem 2.5rem 280px'` for left-nav offset.
207
+ * Without `disablePadding`, the container's `3rem 2rem` stacks with the shell
208
+ * padding and reduces effective content width (e.g. 1200px ContentContainer
209
+ * minus 64px container padding minus 320px shell padding ≈ 816px actual).
210
+ *
211
+ * Added in v0.3.0 (2026-05-24) after ERP Overview Phase 1.13 surfaced the
212
+ * left-nav stacking conflict.
213
+ */
214
+ disablePadding?: boolean;
215
+ /** Optional className for additional styling. */
216
+ className?: string;
217
+ /** Children to render inside the container. */
218
+ children: ReactNode;
219
+ }
220
+ /**
221
+ * Content container that applies the right max-width + padding for its content
222
+ * density tier per DESIGN-STANDARD v2.4 §Content Density Tiers.
223
+ *
224
+ * Per the spec:
225
+ * - Component override > page override > app default (most-specific wins)
226
+ * - Cards INHERIT the parent container's max-width — they do NOT set their own
227
+ *
228
+ * Typical app usage in `src/app/layout.tsx`:
229
+ *
230
+ * ```tsx
231
+ * <main id="main" style={{ marginTop: 44 }}>
232
+ * <ContentContainer>{children}</ContentContainer>
233
+ * </main>
234
+ * ```
235
+ *
236
+ * Per-page override (rare):
237
+ *
238
+ * ```tsx
239
+ * // A wide-table page within an otherwise-reference app
240
+ * <ContentContainer tier="data">
241
+ * <DataTable ... />
242
+ * </ContentContainer>
243
+ * ```
244
+ */
245
+ declare function ContentContainer({ tier, disablePadding, className, children, }: ContentContainerProps): react_jsx_runtime.JSX.Element;
246
+
247
+ export { type App, AppsDropdown, type AppsDropdownProps, type AppsResponse, BackToLauncher, type BackToLauncherProps, ContentContainer, type ContentContainerProps, type ContentTier, type RawApp, TopBar, type TopBarProps, type UseAppsOptions, type UseAppsResult, XzibitMark, type XzibitMarkProps, normalizeApp, useApps };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
2
3
 
3
4
  interface TopBarProps {
4
5
  /** App display name shown in the wordmark slot (e.g. "ERP Overview"). */
@@ -181,4 +182,66 @@ interface UseAppsOptions {
181
182
  */
182
183
  declare function useApps(options?: UseAppsOptions): UseAppsResult;
183
184
 
184
- export { type App, AppsDropdown, type AppsDropdownProps, type AppsResponse, BackToLauncher, type BackToLauncherProps, type RawApp, TopBar, type TopBarProps, type UseAppsOptions, type UseAppsResult, XzibitMark, type XzibitMarkProps, normalizeApp, useApps };
185
+ /**
186
+ * Content density tier per DESIGN-STANDARD v2.4 §Content Density Tiers.
187
+ *
188
+ * - `'editorial'`: 720px max-width — marketing / public-facing docs / long-form prose
189
+ * - `'reference'` (DEFAULT): 1200px max-width — internal docs / wikis / dashboards / most app pages
190
+ * - `'data'`: unconstrained with 32px min side padding — wide tables / kanban / calendars / heatmaps
191
+ */
192
+ type ContentTier = 'editorial' | 'reference' | 'data';
193
+ interface ContentContainerProps {
194
+ /**
195
+ * Content density tier — picks max-width + padding.
196
+ * Defaults to `'reference'` (the portfolio default per v2.4).
197
+ */
198
+ tier?: ContentTier;
199
+ /**
200
+ * If `true`, render no padding — useful when the parent app shell already
201
+ * provides layout-level padding (e.g. left-nav offset).
202
+ *
203
+ * Default: `false` (tier padding is applied).
204
+ *
205
+ * **Common use case:** app-shell `layout.tsx` integration where the surrounding
206
+ * layout div sets `padding: '2.5rem 2.5rem 2.5rem 280px'` for left-nav offset.
207
+ * Without `disablePadding`, the container's `3rem 2rem` stacks with the shell
208
+ * padding and reduces effective content width (e.g. 1200px ContentContainer
209
+ * minus 64px container padding minus 320px shell padding ≈ 816px actual).
210
+ *
211
+ * Added in v0.3.0 (2026-05-24) after ERP Overview Phase 1.13 surfaced the
212
+ * left-nav stacking conflict.
213
+ */
214
+ disablePadding?: boolean;
215
+ /** Optional className for additional styling. */
216
+ className?: string;
217
+ /** Children to render inside the container. */
218
+ children: ReactNode;
219
+ }
220
+ /**
221
+ * Content container that applies the right max-width + padding for its content
222
+ * density tier per DESIGN-STANDARD v2.4 §Content Density Tiers.
223
+ *
224
+ * Per the spec:
225
+ * - Component override > page override > app default (most-specific wins)
226
+ * - Cards INHERIT the parent container's max-width — they do NOT set their own
227
+ *
228
+ * Typical app usage in `src/app/layout.tsx`:
229
+ *
230
+ * ```tsx
231
+ * <main id="main" style={{ marginTop: 44 }}>
232
+ * <ContentContainer>{children}</ContentContainer>
233
+ * </main>
234
+ * ```
235
+ *
236
+ * Per-page override (rare):
237
+ *
238
+ * ```tsx
239
+ * // A wide-table page within an otherwise-reference app
240
+ * <ContentContainer tier="data">
241
+ * <DataTable ... />
242
+ * </ContentContainer>
243
+ * ```
244
+ */
245
+ declare function ContentContainer({ tier, disablePadding, className, children, }: ContentContainerProps): react_jsx_runtime.JSX.Element;
246
+
247
+ export { type App, AppsDropdown, type AppsDropdownProps, type AppsResponse, BackToLauncher, type BackToLauncherProps, ContentContainer, type ContentContainerProps, type ContentTier, type RawApp, TopBar, type TopBarProps, type UseAppsOptions, type UseAppsResult, XzibitMark, type XzibitMarkProps, normalizeApp, useApps };
package/dist/index.js CHANGED
@@ -528,9 +528,36 @@ function BuildBadge({
528
528
  }
529
529
  );
530
530
  }
531
+
532
+ // src/ContentContainer.tsx
533
+ import { jsx as jsx5 } from "react/jsx-runtime";
534
+ var TIER_MAX_WIDTH = {
535
+ editorial: 720,
536
+ reference: 1200,
537
+ data: "100%"
538
+ };
539
+ var TIER_PADDING = {
540
+ editorial: "3rem 2rem",
541
+ reference: "3rem 2rem",
542
+ data: "1.5rem 2rem"
543
+ };
544
+ function ContentContainer({
545
+ tier = "reference",
546
+ disablePadding = false,
547
+ className,
548
+ children
549
+ }) {
550
+ const style = {
551
+ maxWidth: TIER_MAX_WIDTH[tier],
552
+ margin: "0 auto",
553
+ ...disablePadding ? {} : { padding: TIER_PADDING[tier] }
554
+ };
555
+ return /* @__PURE__ */ jsx5("div", { className, style, children });
556
+ }
531
557
  export {
532
558
  AppsDropdown,
533
559
  BackToLauncher,
560
+ ContentContainer,
534
561
  TopBar,
535
562
  XzibitMark,
536
563
  normalizeApp,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xzibit/ui",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Shared chrome components for the Xzibit Apps portfolio. v0.1: TopBar + BackToLauncher + AppsDropdown + XzibitMark + useApps hook. Single source of truth for portfolio chrome — tweak once, every app picks it up on next deploy.",
5
5
  "license": "MIT",
6
6
  "author": "Xzibit Apps",