@deepfuture/dui-components 0.0.15 → 0.0.17

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/README.md CHANGED
@@ -146,6 +146,36 @@ DUI uses CSS custom properties for theming. Toggle dark mode by adding `class="d
146
146
  </body>
147
147
  ```
148
148
 
149
+ ## Templates
150
+
151
+ Pre-composed UI patterns built from DUI components — ready-to-use cards, feed items, and other building blocks. Templates are theme-scoped: they use the default theme's variant vocabulary and tokens, so they adapt automatically to dark mode and custom token overrides.
152
+
153
+ ```bash
154
+ npm install @deepfuture/dui-theme-default-templates
155
+ ```
156
+
157
+ ```typescript
158
+ import { DuiFeedItem } from "@deepfuture/dui-theme-default-templates/feed";
159
+
160
+ applyTheme({
161
+ theme: defaultTheme,
162
+ components: [DuiFeedItem], // dependencies (DuiBadge, etc.) auto-register
163
+ });
164
+ ```
165
+
166
+ ```html
167
+ <dui-feed-item
168
+ title="Earthquake detected"
169
+ subtitle="USGS Pacific Northwest"
170
+ timestamp="2 min ago"
171
+ category="Seismic"
172
+ severity="high"
173
+ description="Magnitude 4.2 recorded near Portland, OR."
174
+ ></dui-feed-item>
175
+ ```
176
+
177
+ Templates declare their component dependencies via `static dependencies` — `applyTheme` auto-registers them, so you don't need to import `DuiBadge` separately.
178
+
149
179
  ## Packages
150
180
 
151
181
  | Package | Purpose |
@@ -153,6 +183,7 @@ DUI uses CSS custom properties for theming. Toggle dark mode by adding `class="d
153
183
  | [`@deepfuture/dui-core`](https://www.npmjs.com/package/@deepfuture/dui-core) | `applyTheme()`, event factory, base styles |
154
184
  | [`@deepfuture/dui-components`](https://www.npmjs.com/package/@deepfuture/dui-components) | Unstyled component classes |
155
185
  | [`@deepfuture/dui-theme-default`](https://www.npmjs.com/package/@deepfuture/dui-theme-default) | Design tokens + aesthetic styles |
186
+ | [`@deepfuture/dui-theme-default-templates`](https://www.npmjs.com/package/@deepfuture/dui-theme-default-templates) | Pre-composed UI patterns for the default theme |
156
187
  | [`@deepfuture/dui-cdn`](https://www.npmjs.com/package/@deepfuture/dui-cdn) | Pre-bundled CDN build (all deps inlined) |
157
188
 
158
189
  ## Dev Tools
@@ -177,6 +208,7 @@ See **[Inspector docs](docs/inspector.md)** for the full API reference and usage
177
208
  - **[Live Docs](https://deepfuturenow.github.io/dui/)** — interactive demos for every component
178
209
  - [Architecture](docs/architecture.md) — mental model, package responsibilities, design decisions
179
210
  - [Creating Components](docs/creating-components.md) — guide for adding new components
211
+ - [Creating Templates](docs/creating-templates.md) — guide for building theme-scoped templates
180
212
  - [Theming](docs/theming.md) — theme system, design tokens, writing component styles
181
213
  - [Consuming](docs/consuming.md) — integrating DUI into an app
182
214
  - [Inspector](docs/inspector.md) — runtime inspection, mutation API, and visual editor
@@ -67,29 +67,12 @@ const styles = css `
67
67
  cursor: default;
68
68
  }
69
69
 
70
- [part="indicator"] {
71
- flex-shrink: 0;
72
- }
73
-
74
70
  [part="panel"] {
75
71
  overflow: hidden;
72
+ contain: content;
76
73
  transition-property: height;
77
74
  }
78
75
  `;
79
- // Inline chevron-down SVG to avoid icon component dependency
80
- const chevronSvg = html `<svg
81
- part="indicator"
82
- width="16"
83
- height="16"
84
- viewBox="0 0 24 24"
85
- fill="none"
86
- stroke="currentColor"
87
- stroke-width="2"
88
- stroke-linecap="round"
89
- stroke-linejoin="round"
90
- >
91
- <path d="m6 9 6 6 6-6" />
92
- </svg>`;
93
76
  let DuiAccordionItem = (() => {
94
77
  let _classSuper = LitElement;
95
78
  let _value_decorators;
@@ -291,7 +274,6 @@ let DuiAccordionItem = (() => {
291
274
  @keydown=${this.#onKeyDown}
292
275
  >
293
276
  <slot name="trigger"></slot>
294
- ${chevronSvg}
295
277
  </button>
296
278
  </h3>
297
279
  ${shouldRender
package/all.d.ts CHANGED
@@ -62,6 +62,8 @@ export { DuiMenubar };
62
62
  export type { MenubarContext } from "./menubar/index.js";
63
63
  import { DuiNumberField } from "./number-field/index.js";
64
64
  export { DuiNumberField };
65
+ import { DuiStepper } from "./stepper/index.js";
66
+ export { DuiStepper };
65
67
  import { DuiPopover, DuiPopoverTrigger, DuiPopoverPopup, DuiPopoverClose } from "./popover/index.js";
66
68
  export { DuiPopover, DuiPopoverTrigger, DuiPopoverPopup, DuiPopoverClose, };
67
69
  export type { PopoverOpenChangeDetail, PopoverContext, PopoverSide, } from "./popover/index.js";
@@ -83,6 +85,8 @@ export { DuiSelect };
83
85
  export type { SelectOption } from "./select/index.js";
84
86
  import { DuiSeparator } from "./separator/index.js";
85
87
  export { DuiSeparator };
88
+ import { DuiSplitButton } from "./split-button/index.js";
89
+ export { DuiSplitButton };
86
90
  import { DuiSidebarProvider, DuiSidebar, DuiSidebarTrigger, DuiSidebarContent, DuiSidebarHeader, DuiSidebarFooter, DuiSidebarGroup, DuiSidebarGroupLabel, DuiSidebarMenu, DuiSidebarMenuItem, DuiSidebarMenuButton, DuiSidebarSeparator, DuiSidebarInset } from "./sidebar/index.js";
87
91
  export { DuiSidebarProvider, DuiSidebar, DuiSidebarTrigger, DuiSidebarContent, DuiSidebarHeader, DuiSidebarFooter, DuiSidebarGroup, DuiSidebarGroupLabel, DuiSidebarMenu, DuiSidebarMenuItem, DuiSidebarMenuButton, DuiSidebarSeparator, DuiSidebarInset, };
88
92
  export type { SidebarContext } from "./sidebar/index.js";
package/all.js CHANGED
@@ -71,6 +71,9 @@ export { DuiMenubar };
71
71
  // --- Number Field ---
72
72
  import { DuiNumberField } from "./number-field/index.js";
73
73
  export { DuiNumberField };
74
+ // --- Stepper ---
75
+ import { DuiStepper } from "./stepper/index.js";
76
+ export { DuiStepper };
74
77
  // --- Popover ---
75
78
  import { DuiPopover, DuiPopoverTrigger, DuiPopoverPopup, DuiPopoverClose, } from "./popover/index.js";
76
79
  export { DuiPopover, DuiPopoverTrigger, DuiPopoverPopup, DuiPopoverClose, };
@@ -95,6 +98,9 @@ export { DuiSelect };
95
98
  // --- Separator ---
96
99
  import { DuiSeparator } from "./separator/index.js";
97
100
  export { DuiSeparator };
101
+ // --- Split Button ---
102
+ import { DuiSplitButton } from "./split-button/index.js";
103
+ export { DuiSplitButton };
98
104
  // --- Sidebar ---
99
105
  import { DuiSidebarProvider, DuiSidebar, DuiSidebarTrigger, DuiSidebarContent, DuiSidebarHeader, DuiSidebarFooter, DuiSidebarGroup, DuiSidebarGroupLabel, DuiSidebarMenu, DuiSidebarMenuItem, DuiSidebarMenuButton, DuiSidebarSeparator, DuiSidebarInset, } from "./sidebar/index.js";
100
106
  export { DuiSidebarProvider, DuiSidebar, DuiSidebarTrigger, DuiSidebarContent, DuiSidebarHeader, DuiSidebarFooter, DuiSidebarGroup, DuiSidebarGroupLabel, DuiSidebarMenu, DuiSidebarMenuItem, DuiSidebarMenuButton, DuiSidebarSeparator, DuiSidebarInset, };
@@ -171,6 +177,7 @@ export const allComponents = [
171
177
  DuiMenuItem,
172
178
  DuiMenubar,
173
179
  DuiNumberField,
180
+ DuiStepper,
174
181
  DuiPopover,
175
182
  DuiPopoverTrigger,
176
183
  DuiPopoverPopup,
@@ -185,6 +192,7 @@ export const allComponents = [
185
192
  DuiScrollArea,
186
193
  DuiSelect,
187
194
  DuiSeparator,
195
+ DuiSplitButton,
188
196
  DuiSidebarProvider,
189
197
  DuiSidebar,
190
198
  DuiSidebarTrigger,
@@ -0,0 +1,17 @@
1
+ import { LitElement, type TemplateResult } from "lit";
2
+ /**
3
+ * `<dui-card-grid>` — A responsive grid layout for cards and panels.
4
+ *
5
+ * Distributes children into equal-width columns that collapse at narrow
6
+ * container widths. Use `columns` to set the maximum column count.
7
+ *
8
+ * @slot - Grid children (cards, panels, or any block content).
9
+ * @csspart root - The grid container element.
10
+ */
11
+ export declare class DuiCardGrid extends LitElement {
12
+ static tagName: "dui-card-grid";
13
+ static styles: import("lit").CSSResult[];
14
+ /** Maximum number of columns (1–4). Responsive breakpoints reduce this automatically. */
15
+ accessor columns: string;
16
+ render(): TemplateResult;
17
+ }
@@ -0,0 +1,110 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { css, html, LitElement } from "lit";
36
+ import { property } from "lit/decorators.js";
37
+ import { base } from "@deepfuture/dui-core/base";
38
+ /** Structural styles only — layout CSS. */
39
+ const styles = css `
40
+ :host {
41
+ display: block;
42
+ min-width: 100%;
43
+ }
44
+
45
+ [part="root"] {
46
+ display: grid;
47
+ grid-template-columns: repeat(var(--_columns, 3), 1fr);
48
+ box-sizing: border-box;
49
+ }
50
+
51
+ :host([columns="1"]) { --_columns: 1; }
52
+ :host([columns="2"]) { --_columns: 2; }
53
+ :host([columns="3"]) { --_columns: 3; }
54
+ :host([columns="4"]) { --_columns: 4; }
55
+
56
+ /* Responsive collapse: narrow viewports reduce columns */
57
+ @media (max-width: 768px) {
58
+ :host([columns="3"]) { --_columns: 2; }
59
+ :host([columns="4"]) { --_columns: 2; }
60
+ }
61
+
62
+ @media (max-width: 480px) {
63
+ :host([columns="2"]),
64
+ :host([columns="3"]),
65
+ :host([columns="4"]) {
66
+ --_columns: 1;
67
+ }
68
+ }
69
+ `;
70
+ /**
71
+ * `<dui-card-grid>` — A responsive grid layout for cards and panels.
72
+ *
73
+ * Distributes children into equal-width columns that collapse at narrow
74
+ * container widths. Use `columns` to set the maximum column count.
75
+ *
76
+ * @slot - Grid children (cards, panels, or any block content).
77
+ * @csspart root - The grid container element.
78
+ */
79
+ let DuiCardGrid = (() => {
80
+ let _classSuper = LitElement;
81
+ let _columns_decorators;
82
+ let _columns_initializers = [];
83
+ let _columns_extraInitializers = [];
84
+ return class DuiCardGrid extends _classSuper {
85
+ static {
86
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
87
+ _columns_decorators = [property({ reflect: true })];
88
+ __esDecorate(this, null, _columns_decorators, { kind: "accessor", name: "columns", static: false, private: false, access: { has: obj => "columns" in obj, get: obj => obj.columns, set: (obj, value) => { obj.columns = value; } }, metadata: _metadata }, _columns_initializers, _columns_extraInitializers);
89
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
90
+ }
91
+ static tagName = "dui-card-grid";
92
+ static styles = [base, styles];
93
+ #columns_accessor_storage = __runInitializers(this, _columns_initializers, "3");
94
+ /** Maximum number of columns (1–4). Responsive breakpoints reduce this automatically. */
95
+ get columns() { return this.#columns_accessor_storage; }
96
+ set columns(value) { this.#columns_accessor_storage = value; }
97
+ render() {
98
+ return html `
99
+ <div part="root">
100
+ <slot></slot>
101
+ </div>
102
+ `;
103
+ }
104
+ constructor() {
105
+ super(...arguments);
106
+ __runInitializers(this, _columns_extraInitializers);
107
+ }
108
+ };
109
+ })();
110
+ export { DuiCardGrid };
@@ -0,0 +1,3 @@
1
+ import { DuiCardGrid } from "./card-grid.js";
2
+ export { DuiCardGrid };
3
+ export declare const cardGridFamily: (typeof DuiCardGrid)[];
@@ -0,0 +1,3 @@
1
+ import { DuiCardGrid } from "./card-grid.js";
2
+ export { DuiCardGrid };
3
+ export const cardGridFamily = [DuiCardGrid];
@@ -65,29 +65,17 @@ const styles = css `
65
65
  cursor: default;
66
66
  }
67
67
 
68
- [part="indicator"] {
69
- flex-shrink: 0;
68
+ slot[name="trigger"] {
69
+ flex: 1;
70
+ min-width: 0;
70
71
  }
71
72
 
72
73
  [part="panel"] {
73
74
  overflow: hidden;
75
+ contain: content;
74
76
  transition-property: height;
75
77
  }
76
78
  `;
77
- // Inline chevron-down SVG to avoid icon component dependency
78
- const chevronSvg = html `<svg
79
- part="indicator"
80
- width="16"
81
- height="16"
82
- viewBox="0 0 24 24"
83
- fill="none"
84
- stroke="currentColor"
85
- stroke-width="2"
86
- stroke-linecap="round"
87
- stroke-linejoin="round"
88
- >
89
- <path d="m6 9 6 6 6-6" />
90
- </svg>`;
91
79
  let DuiCollapsible = (() => {
92
80
  let _classSuper = LitElement;
93
81
  let _open_decorators;
@@ -276,7 +264,6 @@ let DuiCollapsible = (() => {
276
264
  @click=${this.#onClick}
277
265
  >
278
266
  <slot name="trigger"></slot>
279
- ${chevronSvg}
280
267
  </button>
281
268
  ${shouldRender
282
269
  ? html `
@@ -42,7 +42,7 @@ const styles = css `
42
42
  display: block;
43
43
  }
44
44
 
45
- :host([data-hidden]) {
45
+ :host([data-hidden]) .Empty {
46
46
  display: none;
47
47
  }
48
48
 
@@ -45,7 +45,7 @@ const styles = css `
45
45
  display: block;
46
46
  }
47
47
 
48
- :host([data-hidden]) {
48
+ :host([data-hidden]) .Group {
49
49
  display: none;
50
50
  }
51
51
 
@@ -45,7 +45,7 @@ const styles = css `
45
45
  display: block;
46
46
  }
47
47
 
48
- :host([data-hidden]) {
48
+ :host([data-hidden]) .Item {
49
49
  display: none;
50
50
  }
51
51
 
@@ -1,3 +1,3 @@
1
- import { DuiNumberField, valueChangeEvent } from "./number-field.js";
2
- export { DuiNumberField, valueChangeEvent };
1
+ import { DuiNumberField, valueChangeEvent, valueCommittedEvent } from "./number-field.js";
2
+ export { DuiNumberField, valueChangeEvent, valueCommittedEvent };
3
3
  export declare const numberFieldFamily: (typeof DuiNumberField)[];
@@ -1,3 +1,3 @@
1
- import { DuiNumberField, valueChangeEvent } from "./number-field.js";
2
- export { DuiNumberField, valueChangeEvent };
1
+ import { DuiNumberField, valueChangeEvent, valueCommittedEvent, } from "./number-field.js";
2
+ export { DuiNumberField, valueChangeEvent, valueCommittedEvent };
3
3
  export const numberFieldFamily = [DuiNumberField];
@@ -5,14 +5,24 @@ export declare const valueChangeEvent: (detail: {
5
5
  }) => CustomEvent<{
6
6
  value: number;
7
7
  }>;
8
+ export declare const valueCommittedEvent: (detail: {
9
+ value: number;
10
+ }) => CustomEvent<{
11
+ value: number;
12
+ }>;
8
13
  /**
9
- * `<dui-number-field>` — A numeric input with increment/decrement buttons.
14
+ * `<dui-number-field>` — A numeric input with optional label, icon,
15
+ * unit suffix, drag-to-scrub behavior, and precision formatting.
16
+ *
17
+ * For simple step-up/step-down with buttons, use `<dui-stepper>` instead.
10
18
  *
11
19
  * @csspart root - The outer container.
20
+ * @csspart label - Label text element.
21
+ * @csspart icon - Icon slot wrapper.
12
22
  * @csspart input - The text input element.
13
- * @csspart decrement - The decrement button.
14
- * @csspart increment - The increment button.
23
+ * @csspart unit - Unit suffix element.
15
24
  * @fires value-change - Fired when value changes. Detail: { value: number }
25
+ * @fires value-committed - Fired on pointerup (end of drag), blur, or Enter. Detail: { value: number }
16
26
  */
17
27
  export declare class DuiNumberField extends LitElement {
18
28
  #private;
@@ -29,6 +39,17 @@ export declare class DuiNumberField extends LitElement {
29
39
  accessor readOnly: boolean;
30
40
  accessor required: boolean;
31
41
  accessor name: string | undefined;
42
+ accessor label: string;
43
+ accessor labelPosition: string;
44
+ accessor iconPosition: string;
45
+ accessor unit: string;
46
+ accessor precision: number | undefined;
47
+ accessor scrubLabel: boolean;
48
+ accessor scrubValue: boolean;
49
+ accessor scrubField: boolean;
50
+ accessor clickLabel: boolean;
51
+ accessor clickValue: boolean;
52
+ accessor clickField: boolean;
32
53
  accessor _fieldCtx: FieldContext;
33
54
  connectedCallback(): void;
34
55
  willUpdate(): void;