@ptblink/platform-ui
v0.5.6
Published
PT Blink platform Glass component library — extracted from ptb-platform-client-web. Glassmorphism primitives, theme provider, and the useTheme hook for Next.js + Tailwind v4 apps.
Readme
@ptblink/platform-ui
PT Blink's Glass component library — extracted from ptb-platform-client-web. 49 primitives that share a single visual recipe: translucent fill, backdrop blur, 1px hairline border, light/dark theme via a shared useTheme() hook.
Install
pnpm add @ptblink/platform-uiPeers (you provide these):
pnpm add react@^19 react-dom@^19 next@^16 tailwindcss@^4Optional peers — only required if you import from the matching subpath:
| Component(s) | Subpath | Peer |
|---|---|---|
| GlassDonutKpi, GlassMixedSeries, GlassStackedBar | @ptblink/platform-ui/charts | react-apexcharts + apexcharts |
| GlassPdfPreview | @ptblink/platform-ui/pdf | pdfjs-dist |
| GlassCard3D | main barrel | framer-motion |
| GlassExpandableToolbar, GlassRightToolbar | main barrel | react-draggable |
Wire it up
Wrap your app root in
<GlassThemeProvider>— once. Every Glass component downstream readsthemefrom it.// app/layout.tsx import { GlassThemeProvider } from "@ptblink/platform-ui"; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body data-theme="dark"> <GlassThemeProvider>{children}</GlassThemeProvider> </body> </html> ); }Import the stylesheet for the small set of scrollbar helpers used by dropdowns / scroll areas:
/* app/globals.css */ @import "@ptblink/platform-ui/styles.css";Use a primitive:
"use client"; import { GlassCard, GlassButton, useTheme } from "@ptblink/platform-ui"; export default function Example() { const { theme, setTheme } = useTheme(); return ( <GlassCard> <button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}> Toggle theme </button> <GlassButton>Action</GlassButton> </GlassCard> ); }
Exported surface
Theme
GlassThemeProvider— ownstheme: "light" | "dark"and persists tolocalStorage["ptb-theme"].ThemeContext— the underlying context (advanced usage).useTheme()→{ theme, setTheme, getThemeClasses }.
Hooks
useDockSide(ref, options?)→{ side, vertical, update }— for floating toolbars/panels that flip based on viewport position.
Components — @ptblink/platform-ui
| Category | Exports |
|---|---|
| Backgrounds | GlassBackdrop, GlassFullscreenBackground |
| Buttons | GlassButton, GlassDropdownSelectButton |
| Cards | GlassCard, GlassCard3D, GlassHoverCard, GlassWidgetCard |
| Forms | GlassForm, GlassFormCompact, GlassPopUpForm |
| Inputs | GlassAutofillBox, GlassCheckbox, GlassDividedAutofillBox, GlassDropdown, GlassInput, GlassInputBar, GlassToggleDropdown |
| Labels | GlassPillLabel |
| Modals | GlassConfirmModal, GlassModal |
| Other | GlassExpandableToolbar, GlassIndicatorDot, GlassRangeBarTimeline, GlassScrollArea, GlassStepperDots, GlassTooltip |
| Sections | GlassBrandingSection, GlassPanel, GlassSection, GlassToolPanel |
| Tables | GlassTable, GlassTableAligned, GlassTableInput |
| Tabs | GlassMultiTabs, GlassScrollableTabs, GlassTabSection, GlassTabs |
| Toolbars | GlassRightToolbar, GlassToolbar, GlassToolbarButton |
| Companion | DesktopOnly, PtbIndicator |
Components — @ptblink/platform-ui/charts (opt-in)
GlassDonutKpi, GlassMixedSeries, GlassStackedBar
Components — @ptblink/platform-ui/pdf (opt-in)
GlassPdfPreview
Not included (intentionally domain-coupled)
These four primitives live in ptb-platform-client-web and stay there — they're wired to product-specific state and would force consuming apps to adopt parts of the platform stack:
GlassASTInput(1066-line PTB formula editor)GlassBOMPickerButton(companion to the AST editor)GlassPhotoUpload(Azure Blob client)GlassPageHeader(AuthContext + hardcoded brand)GlassThemeToggle(this package ships its own theme provider; the original writes to a domainUiContext)
Caveats
- The whole barrel is
"use client". Each entry (index.js,charts.js,pdf.js) gets the directive prepended at build time so the package works in Next.js App Router server contexts. Pure-server components likeGlassIndicatorDotstill render correctly but ship to the client bundle. - Theme classes are runtime, not Tailwind variants. The Glass system uses
getThemeClasses()to swap class strings per theme — nodark:prefix anywhere. This means your Tailwind config doesn't needdarkModeconfigured, but it also means you can't combine Glass components with customdark:selectors expecting the same theme value unless you mirror the active theme yourself. GlassInput.classNametargets the wrapper<div>, not the inner<input>. Preserved verbatim from the source — fix in a future major.GlassScrollableTabsuses<style jsx>. Works inside Next.js (which bundles styled-jsx). Outside Next, the styles won't apply; consider forking that component if you need it in a non-Next host.
