@deepfuture/dui-cdn 0.0.11 → 0.0.13

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.
Files changed (4) hide show
  1. package/README.md +183 -0
  2. package/dui.js +49 -38
  3. package/dui.min.js +125 -121
  4. package/package.json +2 -2
package/README.md ADDED
@@ -0,0 +1,183 @@
1
+ # DUI
2
+
3
+ [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
4
+ [![npm](https://img.shields.io/npm/v/@deepfuture/dui-core.svg)](https://www.npmjs.com/package/@deepfuture/dui-core)
5
+
6
+ Unstyled [Lit](https://lit.dev) web component library with composable themes.
7
+
8
+ Components provide structure and behavior with zero visual opinions. Themes provide all aesthetics — colors, spacing, typography, borders. Swap the theme to completely change the look without touching component code.
9
+
10
+ **[Live Docs & Demos →](https://deepfuturenow.github.io/dui/)**
11
+
12
+ ## Install
13
+
14
+ **npm / pnpm / yarn:**
15
+
16
+ ```bash
17
+ npm install @deepfuture/dui-core @deepfuture/dui-components @deepfuture/dui-theme-default
18
+ ```
19
+
20
+ **Deno:**
21
+
22
+ ```typescript
23
+ import { applyTheme } from "npm:@deepfuture/dui-core/apply-theme";
24
+ import { defaultTheme } from "npm:@deepfuture/dui-theme-default";
25
+ import { allComponents } from "npm:@deepfuture/dui-components/all";
26
+ ```
27
+
28
+ **CDN (zero setup):**
29
+
30
+ ```html
31
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@deepfuture/dui-cdn/dui.min.js"></script>
32
+ ```
33
+
34
+ ## Quick Start
35
+
36
+ ```typescript
37
+ import { applyTheme } from "@deepfuture/dui-core/apply-theme";
38
+ import { defaultTheme } from "@deepfuture/dui-theme-default";
39
+ import { DuiButton } from "@deepfuture/dui-components/button";
40
+ import { DuiDialog, DuiDialogTrigger, DuiDialogPopup, DuiDialogClose } from "@deepfuture/dui-components/dialog";
41
+
42
+ // Register components with a theme — this is the only setup needed
43
+ applyTheme({
44
+ theme: defaultTheme,
45
+ components: [DuiButton, DuiDialog, DuiDialogTrigger, DuiDialogPopup, DuiDialogClose],
46
+ });
47
+ ```
48
+
49
+ ```html
50
+ <dui-dialog>
51
+ <dui-dialog-trigger>
52
+ <dui-button>Open Dialog</dui-button>
53
+ </dui-dialog-trigger>
54
+ <dui-dialog-popup>
55
+ <h2>Hello</h2>
56
+ <p>This is a dialog.</p>
57
+ <dui-dialog-close>
58
+ <dui-button variant="outline">Close</dui-button>
59
+ </dui-dialog-close>
60
+ </dui-dialog-popup>
61
+ </dui-dialog>
62
+ ```
63
+
64
+ Or register everything at once:
65
+
66
+ ```typescript
67
+ import { applyTheme } from "@deepfuture/dui-core/apply-theme";
68
+ import { defaultTheme } from "@deepfuture/dui-theme-default";
69
+ import { allComponents } from "@deepfuture/dui-components/all";
70
+
71
+ applyTheme({ theme: defaultTheme, components: allComponents });
72
+ ```
73
+
74
+ ## How It Works
75
+
76
+ `applyTheme()` takes unstyled component classes and a theme, creates themed subclasses with composed styles, and registers them as custom elements.
77
+
78
+ ```
79
+ Component structural CSS → Theme base styles → Theme component styles
80
+ ```
81
+
82
+ No build step, no decorators, no code generation — just a function call. Components are standard web components that work in any framework or plain HTML.
83
+
84
+ ## Components
85
+
86
+ 43 component families, 85+ elements total.
87
+
88
+ | Category | Components |
89
+ |----------|-----------|
90
+ | **Actions** | Button, Link, Toggle, Toggle Group, Toolbar |
91
+ | **Forms** | Input, Textarea, Select, Combobox, Checkbox, Checkbox Group, Radio, Radio Group, Switch, Slider, Number Field, Dropzone |
92
+ | **Data Display** | Badge, Avatar, Calendar, Data Table, Progress, Spinner, Separator, Trunc |
93
+ | **Overlays** | Dialog, Alert Dialog, Popover, Tooltip, Menu, Menubar, Preview Card, Command |
94
+ | **Disclosure** | Accordion, Collapsible, Tabs |
95
+ | **Navigation** | Breadcrumb, Sidebar (with 12 sub-components) |
96
+ | **Layout** | HStack, VStack, Center, Page Inset, Scroll Area, Portal |
97
+ | **Utility** | Icon |
98
+
99
+ ## Styling
100
+
101
+ DUI uses a two-layer styling approach:
102
+
103
+ ### CSS Variables — for the variant system
104
+
105
+ Variables control values that variants, sizes, and states toggle:
106
+
107
+ ```css
108
+ /* Override variant colors */
109
+ dui-button {
110
+ --button-bg: linear-gradient(135deg, pink, purple);
111
+ --button-radius: var(--radius-full);
112
+ }
113
+ ```
114
+
115
+ ### `::part(root)` — for everything else
116
+
117
+ Every component exposes a `root` CSS part for full CSS expressiveness:
118
+
119
+ ```css
120
+ /* Frosted glass effect */
121
+ dui-dialog-popup::part(root) {
122
+ backdrop-filter: blur(12px);
123
+ }
124
+
125
+ /* Custom hover animation */
126
+ dui-button::part(root):hover {
127
+ filter: brightness(1.25);
128
+ transform: translateY(-1px);
129
+ }
130
+
131
+ /* Glow shadow */
132
+ dui-badge::part(root) {
133
+ box-shadow: 0 0 16px oklch(0.7 0.2 280 / 0.4);
134
+ }
135
+ ```
136
+
137
+ No need for the library to anticipate every CSS property — `::part()` gives you direct access.
138
+
139
+ ## Dark Mode
140
+
141
+ DUI uses CSS custom properties for theming. Toggle dark mode by adding `class="dark"` to a parent element:
142
+
143
+ ```html
144
+ <body class="dark">
145
+ <!-- All DUI components render in dark mode -->
146
+ </body>
147
+ ```
148
+
149
+ ## Packages
150
+
151
+ | Package | Purpose |
152
+ |---------|---------|
153
+ | [`@deepfuture/dui-core`](https://www.npmjs.com/package/@deepfuture/dui-core) | `applyTheme()`, event factory, base styles |
154
+ | [`@deepfuture/dui-components`](https://www.npmjs.com/package/@deepfuture/dui-components) | Unstyled component classes |
155
+ | [`@deepfuture/dui-theme-default`](https://www.npmjs.com/package/@deepfuture/dui-theme-default) | Design tokens + aesthetic styles |
156
+ | [`@deepfuture/dui-cdn`](https://www.npmjs.com/package/@deepfuture/dui-cdn) | Pre-bundled CDN build (all deps inlined) |
157
+
158
+ ## Dev Tools
159
+
160
+ ### Theme Editor
161
+
162
+ A visual editor for design tokens. Edit colors with OKLCH sliders, tweak spacing and typography, and export your customized `tokens.css`.
163
+
164
+ ### Inspector
165
+
166
+ Toggle with **Ctrl+Shift+I** to inspect any DUI component at runtime — view properties, design tokens, style layers, slots, and CSS parts. Also exposes `window.__dui_inspect()` for programmatic access by LLM agents via Chrome DevTools.
167
+
168
+ ## Documentation
169
+
170
+ - **[Live Docs](https://deepfuturenow.github.io/dui/)** — interactive demos for every component
171
+ - [Architecture](docs/architecture.md) — mental model, package responsibilities, design decisions
172
+ - [Creating Components](docs/creating-components.md) — guide for adding new components
173
+ - [Theming](docs/theming.md) — theme system, design tokens, writing component styles
174
+ - [Consuming](docs/consuming.md) — integrating DUI into an app
175
+ - [Accessibility](docs/accessibility.md) — accessibility patterns and guidelines
176
+
177
+ ## Contributing
178
+
179
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for dev setup, code conventions, and PR guidelines.
180
+
181
+ ## License
182
+
183
+ [MIT](LICENSE)
package/dui.js CHANGED
@@ -760,7 +760,7 @@ var accordionItemStyles = i`
760
760
 
761
761
  @media (hover: hover) {
762
762
  [part="trigger"]:hover {
763
- background: oklch(from var(--foreground) l c h / 0.04);
763
+ background: oklch(from var(--foreground) l c h / 0.05);
764
764
  }
765
765
  }
766
766
 
@@ -1054,7 +1054,7 @@ var switchStyles = i`
1054
1054
  width: var(--switch-thumb-size);
1055
1055
  height: var(--switch-thumb-size);
1056
1056
  border-radius: 50%;
1057
- outline: 1px solid transparent;
1057
+ outline: var(--border-width-thin) solid transparent;
1058
1058
  background: var(--background);
1059
1059
  transition-property: transform, outline-color;
1060
1060
  transition-duration: var(--duration-fast);
@@ -1158,7 +1158,7 @@ var scrollAreaStyles = i`
1158
1158
  var(--scroll-fade-spread-radius, var(--space-2))
1159
1159
  var(--scroll-fade-color, var(--background));
1160
1160
  opacity: 0;
1161
- transition: opacity 150ms ease;
1161
+ transition: opacity var(--duration-fast) ease;
1162
1162
 
1163
1163
  &[data-scrolled] {
1164
1164
  opacity: 1;
@@ -1166,18 +1166,18 @@ var scrollAreaStyles = i`
1166
1166
  }
1167
1167
 
1168
1168
  .Scrollbar {
1169
- border-radius: var(--radius-sm, 0.375rem);
1170
- transition: opacity 150ms;
1169
+ border-radius: var(--radius-sm);
1170
+ transition: opacity var(--duration-fast);
1171
1171
  }
1172
1172
 
1173
1173
  .Scrollbar[data-orientation="vertical"] {
1174
- width: 0.25rem;
1175
- margin: 0.1rem;
1174
+ width: var(--space-1);
1175
+ margin: var(--space-px);
1176
1176
  }
1177
1177
 
1178
1178
  .Scrollbar[data-orientation="horizontal"] {
1179
- height: 0.25rem;
1180
- margin: 0.1rem;
1179
+ height: var(--space-1);
1180
+ margin: var(--space-px);
1181
1181
  }
1182
1182
 
1183
1183
  .Thumb {
@@ -1231,7 +1231,7 @@ var comboboxStyles = i`
1231
1231
  }
1232
1232
 
1233
1233
  .Input::placeholder {
1234
- color: var(--text-2);
1234
+ color: var(--text-3);
1235
1235
  }
1236
1236
 
1237
1237
  /* Single-select input wrapper */
@@ -1442,12 +1442,12 @@ var tooltipPopupStyles = i`
1442
1442
  var(--foreground) 90%,
1443
1443
  oklch(0 0 0 / 0)
1444
1444
  );
1445
- backdrop-filter: blur(5px);
1445
+ backdrop-filter: var(--filter-blur-sm);
1446
1446
  color: var(--background);
1447
1447
  font-family: var(--font-sans);
1448
1448
  ${type("xs", { lineHeight: "var(--line-height-snug)" })}
1449
1449
  box-shadow: var(--shadow-sm);
1450
- max-width: 20rem;
1450
+ max-width: var(--space-80);
1451
1451
  transition-duration: var(--duration-fastest);
1452
1452
  transition-timing-function: var(--ease-out-3);
1453
1453
  }
@@ -1489,6 +1489,7 @@ var dialogPopupStyles = i`
1489
1489
  background: var(--surface-2);
1490
1490
  color: var(--text-1);
1491
1491
  font-family: var(--font-sans);
1492
+ box-shadow: var(--shadow-lg);
1492
1493
  transition-duration: var(--duration-fast);
1493
1494
  }
1494
1495
 
@@ -1555,6 +1556,7 @@ var alertDialogPopupStyles = i`
1555
1556
  background: var(--surface-2);
1556
1557
  color: var(--text-1);
1557
1558
  font-family: var(--font-sans);
1559
+ box-shadow: var(--shadow-lg);
1558
1560
  transition-duration: var(--duration-fast);
1559
1561
  }
1560
1562
 
@@ -1702,8 +1704,8 @@ var checkboxStyles = i`
1702
1704
  }
1703
1705
 
1704
1706
  .Icon {
1705
- width: 12px;
1706
- height: 12px;
1707
+ width: var(--space-3);
1708
+ height: var(--space-3);
1707
1709
  }
1708
1710
  `;
1709
1711
 
@@ -1739,7 +1741,7 @@ var collapsibleStyles = i`
1739
1741
 
1740
1742
  @media (hover: hover) {
1741
1743
  [part="trigger"]:hover {
1742
- background: oklch(from var(--foreground) l c h / 0.04);
1744
+ background: oklch(from var(--foreground) l c h / 0.05);
1743
1745
  }
1744
1746
  }
1745
1747
 
@@ -1884,7 +1886,7 @@ var sliderStyles = i`
1884
1886
  width: var(--slider-thumb-size);
1885
1887
  height: var(--slider-thumb-size);
1886
1888
  background: var(--background);
1887
- border: 2px solid var(--accent);
1889
+ border: var(--border-width-medium) solid var(--accent);
1888
1890
  border-radius: 50%;
1889
1891
  transition-property: left, box-shadow;
1890
1892
  transition-duration: 50ms, var(--duration-fast);
@@ -1897,7 +1899,7 @@ var sliderStyles = i`
1897
1899
 
1898
1900
  @media (hover: hover) {
1899
1901
  [part="thumb"]:hover {
1900
- box-shadow: 0 0 0 4px color-mix(in oklch, var(--accent) 20%, transparent);
1902
+ box-shadow: 0 0 0 var(--space-1) color-mix(in oklch, var(--accent) 20%, transparent);
1901
1903
  }
1902
1904
  }
1903
1905
 
@@ -1940,7 +1942,7 @@ var tabStyles = i`
1940
1942
  ${type("sm", { lineHeight: "var(--line-height-snug)" })}
1941
1943
  font-weight: var(--font-weight-medium);
1942
1944
  padding-inline: var(--space-2);
1943
- height: 2rem;
1945
+ height: var(--component-height-md);
1944
1946
  transition-property: color, box-shadow, background, filter, transform;
1945
1947
  transition-duration: var(--duration-fast);
1946
1948
  }
@@ -1974,10 +1976,10 @@ var tabsStyles = i``;
1974
1976
  // packages/theme-default/src/components/tabs-indicator.ts
1975
1977
  var tabsIndicatorStyles = i`
1976
1978
  :host {
1977
- height: 1.5rem;
1979
+ height: var(--space-6);
1978
1980
  border-radius: var(--radius-sm);
1979
1981
  background: oklch(from var(--foreground) l c h / 0.08);
1980
- transition-duration: 200ms;
1982
+ transition-duration: var(--duration-normal);
1981
1983
  transition-timing-function: var(--ease-in-out-3);
1982
1984
  }
1983
1985
  `;
@@ -2060,7 +2062,7 @@ var textareaStyles = i`
2060
2062
  }
2061
2063
 
2062
2064
  [part="textarea"]::placeholder {
2063
- color: var(--text-2);
2065
+ color: var(--text-3);
2064
2066
  }
2065
2067
 
2066
2068
  [part="textarea"]:focus-visible {
@@ -2223,8 +2225,8 @@ var radioStyles = i`
2223
2225
  }
2224
2226
 
2225
2227
  [part="dot"] {
2226
- width: 8px;
2227
- height: 8px;
2228
+ width: var(--space-2);
2229
+ height: var(--space-2);
2228
2230
  border-radius: 50%;
2229
2231
  background: oklch(from var(--accent) 0.98 0.01 h);
2230
2232
  }
@@ -2244,7 +2246,7 @@ var dropzoneStyles = i`
2244
2246
  }
2245
2247
 
2246
2248
  [part="root"] {
2247
- border: 2px dashed var(--border);
2249
+ border: var(--border-width-medium) dashed var(--border);
2248
2250
  border-radius: var(--radius-md);
2249
2251
  background: var(--background);
2250
2252
  color: var(--text-1);
@@ -2307,7 +2309,7 @@ var selectStyles = i`
2307
2309
  }
2308
2310
 
2309
2311
  .Value[data-placeholder] {
2310
- color: var(--text-2);
2312
+ color: var(--text-3);
2311
2313
  }
2312
2314
 
2313
2315
  .Icon {
@@ -2465,7 +2467,7 @@ var dataTableStyles = i`
2465
2467
  }
2466
2468
 
2467
2469
  .EmptyRow td {
2468
- height: 96px;
2470
+ height: var(--space-24);
2469
2471
  text-align: center;
2470
2472
  color: var(--text-2);
2471
2473
  }
@@ -2500,7 +2502,7 @@ var dataTableStyles = i`
2500
2502
  }
2501
2503
 
2502
2504
  .PageButton:disabled {
2503
- opacity: 0.3;
2505
+ opacity: 0.4;
2504
2506
  }
2505
2507
 
2506
2508
  .PageButton:focus-visible {
@@ -2541,7 +2543,7 @@ var commandInputStyles = i`
2541
2543
  }
2542
2544
 
2543
2545
  .Input::placeholder {
2544
- color: var(--text-2);
2546
+ color: var(--text-3);
2545
2547
  }
2546
2548
  `;
2547
2549
 
@@ -2573,7 +2575,7 @@ var commandItemStyles = i`
2573
2575
  // packages/theme-default/src/components/command-list.ts
2574
2576
  var commandListStyles = i`
2575
2577
  dui-scroll-area {
2576
- max-height: 300px;
2578
+ max-height: calc(var(--space-5) * 15);
2577
2579
  height: auto;
2578
2580
  }
2579
2581
 
@@ -2608,7 +2610,7 @@ var commandEmptyStyles = i`
2608
2610
  // packages/theme-default/src/components/command-separator.ts
2609
2611
  var commandSeparatorStyles = i`
2610
2612
  .Separator {
2611
- height: 1px;
2613
+ height: var(--border-width-thin);
2612
2614
  margin-inline: calc(-1 * var(--space-1));
2613
2615
  background: var(--border);
2614
2616
  }
@@ -2842,7 +2844,7 @@ var sidebarMenuButtonStyles = i`
2842
2844
  color: var(--sidebar-button-fg);
2843
2845
  font-family: var(--font-sans);
2844
2846
  font-size: var(--smb-font-size);
2845
- font-weight: var(--font-weight-normal);
2847
+ font-weight: var(--font-weight-regular);
2846
2848
  letter-spacing: var(--letter-spacing-tight);
2847
2849
  line-height: var(--line-height-snug);
2848
2850
  --icon-size: var(--smb-icon-size);
@@ -2995,14 +2997,15 @@ var numberFieldStyles = i`
2995
2997
  [part="root"] {
2996
2998
  border: var(--border-width-thin) solid var(--border);
2997
2999
  border-radius: var(--radius-md);
2998
- background: var(--background);
3000
+ background: var(--sunken);
2999
3001
  transition-property: border-color, box-shadow;
3000
3002
  transition-duration: var(--duration-fast);
3001
3003
  }
3002
3004
 
3003
3005
  [part="root"]:focus-within {
3004
- border-color: var(--focus-ring-color);
3005
- box-shadow: 0 0 0 var(--focus-ring-width) color-mix(in oklch, var(--focus-ring-color) 25%, transparent);
3006
+ box-shadow:
3007
+ 0 0 0 var(--focus-ring-offset) var(--background),
3008
+ 0 0 0 calc(var(--focus-ring-offset) + var(--focus-ring-width)) var(--focus-ring-color);
3006
3009
  }
3007
3010
 
3008
3011
  [part="root"][data-disabled] {
@@ -3014,7 +3017,7 @@ var numberFieldStyles = i`
3014
3017
  }
3015
3018
 
3016
3019
  [part="input"] {
3017
- height: var(--space-9);
3020
+ height: var(--component-height-md);
3018
3021
  width: var(--space-16);
3019
3022
  font-family: var(--font-sans);
3020
3023
  ${type("sm")}
@@ -3042,7 +3045,7 @@ var numberFieldStyles = i`
3042
3045
 
3043
3046
  [part="decrement"]:disabled,
3044
3047
  [part="increment"]:disabled {
3045
- opacity: 0.3;
3048
+ opacity: 0.4;
3046
3049
  }
3047
3050
  `;
3048
3051
 
@@ -3098,7 +3101,7 @@ var calendarStyles = i`
3098
3101
  width: var(--space-8);
3099
3102
  height: var(--space-8);
3100
3103
  ${type("xs")}
3101
- font-weight: var(--font-weight-normal);
3104
+ font-weight: var(--font-weight-regular);
3102
3105
  color: var(--text-2);
3103
3106
  display: flex;
3104
3107
  align-items: center;
@@ -3137,7 +3140,7 @@ var calendarStyles = i`
3137
3140
  }
3138
3141
 
3139
3142
  [part="day"]:disabled {
3140
- opacity: 0.3;
3143
+ opacity: 0.4;
3141
3144
  }
3142
3145
 
3143
3146
  [part="day"]:focus-visible {
@@ -3303,6 +3306,7 @@ var tokens_default = `/* =======================================================
3303
3306
  * Motion
3304
3307
  * ----------------------------------------------------------- */
3305
3308
  --duration-instant: 50ms;
3309
+ --duration-fastest: 75ms;
3306
3310
  --duration-faster: 100ms;
3307
3311
  --duration-fast: 150ms;
3308
3312
  --duration-normal: 250ms;
@@ -12532,9 +12536,16 @@ var _DuiScrollArea = class _DuiScrollArea extends (_a36 = i4, _orientation_dec3
12532
12536
  __privateGet(this, _resizeObserver).observe(viewport);
12533
12537
  const slot = viewport.querySelector("slot");
12534
12538
  if (slot) {
12539
+ const observe = () => {
12540
+ for (const node of slot.assignedElements()) {
12541
+ __privateGet(this, _resizeObserver).observe(node);
12542
+ }
12543
+ };
12535
12544
  slot.addEventListener("slotchange", () => {
12545
+ observe();
12536
12546
  requestAnimationFrame(() => __privateGet(this, _measure).call(this));
12537
12547
  });
12548
+ observe();
12538
12549
  }
12539
12550
  __privateGet(this, _measure).call(this);
12540
12551
  }