@nuralyui/layout 0.0.1

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.
@@ -0,0 +1,273 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { LitElement, html } from 'lit';
8
+ import { customElement, property, state } from 'lit/decorators.js';
9
+ import { classMap } from 'lit/directives/class-map.js';
10
+ import { NuralyUIBaseMixin } from '../../shared/base-mixin.js';
11
+ import { siderStyles } from './sider.style.js';
12
+ import { BREAKPOINT_VALUES, } from './layout.types.js';
13
+ /**
14
+ * # Sider Component
15
+ *
16
+ * The sidebar component with collapsible functionality, theme support, and responsive behavior.
17
+ * Must be placed inside a Layout component.
18
+ *
19
+ * @element nr-sider
20
+ *
21
+ * @slot - Default slot for sider content (usually navigation menu)
22
+ * @slot trigger - Custom trigger slot (overrides default trigger)
23
+ *
24
+ * @fires collapse - Fired when the sider is collapsed or expanded
25
+ * @fires breakpoint - Fired when the breakpoint is triggered
26
+ *
27
+ * @csspart sider - The sider container element
28
+ * @csspart trigger - The collapse trigger element
29
+ *
30
+ * @example
31
+ * ```html
32
+ * <nr-layout has-sider>
33
+ * <nr-sider collapsible breakpoint="lg">
34
+ * <nav>Navigation Menu</nav>
35
+ * </nr-sider>
36
+ * <nr-content>Content</nr-content>
37
+ * </nr-layout>
38
+ * ```
39
+ */
40
+ let NrSiderElement = class NrSiderElement extends NuralyUIBaseMixin(LitElement) {
41
+ constructor() {
42
+ super(...arguments);
43
+ /**
44
+ * Current collapsed state (controlled)
45
+ */
46
+ this.collapsed = false;
47
+ /**
48
+ * Width when collapsed. Set to 0 for a special trigger.
49
+ */
50
+ this.collapsedWidth = 80;
51
+ /**
52
+ * Whether the sider can be collapsed
53
+ */
54
+ this.collapsible = false;
55
+ /**
56
+ * Initial collapsed state (uncontrolled)
57
+ */
58
+ this.defaultCollapsed = false;
59
+ /**
60
+ * Reverse the arrow direction (for right-side sider)
61
+ */
62
+ this.reverseArrow = false;
63
+ /**
64
+ * Sider theme (light or dark)
65
+ */
66
+ this.theme = "dark" /* SiderTheme.Dark */;
67
+ /**
68
+ * Custom trigger element. Set to null to hide trigger.
69
+ */
70
+ this.trigger = 'default';
71
+ /**
72
+ * Sider width when expanded
73
+ */
74
+ this.width = 200;
75
+ /**
76
+ * Custom styles for zero-width trigger
77
+ */
78
+ this.zeroWidthTriggerStyle = '';
79
+ /**
80
+ * Internal state for tracking if breakpoint is active
81
+ */
82
+ this.belowBreakpoint = false;
83
+ }
84
+ connectedCallback() {
85
+ super.connectedCallback();
86
+ // Set initial collapsed state
87
+ if (this.defaultCollapsed && !this.hasAttribute('collapsed')) {
88
+ this.collapsed = true;
89
+ }
90
+ // Setup resize observer for breakpoint
91
+ if (this.breakpoint) {
92
+ this.setupResizeObserver();
93
+ }
94
+ }
95
+ disconnectedCallback() {
96
+ var _a;
97
+ super.disconnectedCallback();
98
+ (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
99
+ }
100
+ updated(changedProperties) {
101
+ var _a;
102
+ super.updated(changedProperties);
103
+ if (changedProperties.has('breakpoint')) {
104
+ (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
105
+ if (this.breakpoint) {
106
+ this.setupResizeObserver();
107
+ }
108
+ }
109
+ }
110
+ /**
111
+ * Setup ResizeObserver for responsive breakpoint behavior
112
+ */
113
+ setupResizeObserver() {
114
+ if (!this.breakpoint)
115
+ return;
116
+ const breakpointValue = BREAKPOINT_VALUES[this.breakpoint];
117
+ this.resizeObserver = new ResizeObserver((entries) => {
118
+ for (const entry of entries) {
119
+ const width = entry.contentRect.width;
120
+ const shouldBeCollapsed = width < breakpointValue;
121
+ if (shouldBeCollapsed !== this.belowBreakpoint) {
122
+ this.belowBreakpoint = shouldBeCollapsed;
123
+ // Auto-collapse when below breakpoint
124
+ if (this.collapsible && shouldBeCollapsed !== this.collapsed) {
125
+ this.collapsed = shouldBeCollapsed;
126
+ this.dispatchCollapseEvent('responsive');
127
+ }
128
+ // Dispatch breakpoint event
129
+ this.dispatchBreakpointEvent(shouldBeCollapsed);
130
+ }
131
+ }
132
+ });
133
+ // Observe the parent layout or document body
134
+ const target = this.closest('nr-layout') || document.body;
135
+ this.resizeObserver.observe(target);
136
+ }
137
+ /**
138
+ * Toggle collapsed state
139
+ */
140
+ toggleCollapse() {
141
+ this.collapsed = !this.collapsed;
142
+ this.dispatchCollapseEvent('clickTrigger');
143
+ }
144
+ /**
145
+ * Dispatch collapse event
146
+ */
147
+ dispatchCollapseEvent(type) {
148
+ this.dispatchEvent(new CustomEvent('collapse', {
149
+ detail: { collapsed: this.collapsed, type },
150
+ bubbles: true,
151
+ composed: true,
152
+ }));
153
+ }
154
+ /**
155
+ * Dispatch breakpoint event
156
+ */
157
+ dispatchBreakpointEvent(broken) {
158
+ this.dispatchEvent(new CustomEvent('breakpoint', {
159
+ detail: { broken },
160
+ bubbles: true,
161
+ composed: true,
162
+ }));
163
+ }
164
+ /**
165
+ * Get the current width based on collapsed state
166
+ */
167
+ getCurrentWidth() {
168
+ if (this.collapsed) {
169
+ return `${this.collapsedWidth}px`;
170
+ }
171
+ return typeof this.width === 'number' ? `${this.width}px` : this.width.toString();
172
+ }
173
+ /**
174
+ * Render the collapse trigger
175
+ */
176
+ renderTrigger() {
177
+ if (this.trigger === null || !this.collapsible) {
178
+ return null;
179
+ }
180
+ // Check for custom trigger slot
181
+ const hasCustomTrigger = this.querySelector('[slot="trigger"]');
182
+ if (hasCustomTrigger) {
183
+ return html `<slot name="trigger"></slot>`;
184
+ }
185
+ // Zero-width trigger (special trigger when collapsedWidth is 0)
186
+ if (this.collapsedWidth === 0 && this.collapsed) {
187
+ return html `
188
+ <div
189
+ class="nr-sider-zero-width-trigger"
190
+ part="trigger"
191
+ style=${this.zeroWidthTriggerStyle}
192
+ @click=${this.toggleCollapse}
193
+ >
194
+ <span class="trigger-icon">${this.reverseArrow ? '◀' : '▶'}</span>
195
+ </div>
196
+ `;
197
+ }
198
+ // Default trigger
199
+ return html `
200
+ <div
201
+ class="nr-sider-trigger"
202
+ part="trigger"
203
+ @click=${this.toggleCollapse}
204
+ >
205
+ <span class="trigger-icon">
206
+ ${this.collapsed
207
+ ? (this.reverseArrow ? '◀' : '▶')
208
+ : (this.reverseArrow ? '▶' : '◀')}
209
+ </span>
210
+ </div>
211
+ `;
212
+ }
213
+ render() {
214
+ const classes = {
215
+ 'nr-sider': true,
216
+ 'nr-sider-collapsed': this.collapsed,
217
+ 'nr-sider-has-trigger': this.collapsible && this.trigger !== null,
218
+ 'nr-sider-below-breakpoint': this.belowBreakpoint,
219
+ 'nr-sider-zero-width': this.collapsed && this.collapsedWidth === 0,
220
+ };
221
+ return html `
222
+ <aside
223
+ class=${classMap(classes)}
224
+ part="sider"
225
+ style="width: ${this.getCurrentWidth()}; flex: 0 0 ${this.getCurrentWidth()};"
226
+ >
227
+ <div class="nr-sider-children">
228
+ <slot></slot>
229
+ </div>
230
+ ${this.renderTrigger()}
231
+ </aside>
232
+ `;
233
+ }
234
+ };
235
+ NrSiderElement.styles = siderStyles;
236
+ __decorate([
237
+ property({ type: String })
238
+ ], NrSiderElement.prototype, "breakpoint", void 0);
239
+ __decorate([
240
+ property({ type: Boolean, reflect: true })
241
+ ], NrSiderElement.prototype, "collapsed", void 0);
242
+ __decorate([
243
+ property({ type: Number, attribute: 'collapsed-width' })
244
+ ], NrSiderElement.prototype, "collapsedWidth", void 0);
245
+ __decorate([
246
+ property({ type: Boolean })
247
+ ], NrSiderElement.prototype, "collapsible", void 0);
248
+ __decorate([
249
+ property({ type: Boolean, attribute: 'default-collapsed' })
250
+ ], NrSiderElement.prototype, "defaultCollapsed", void 0);
251
+ __decorate([
252
+ property({ type: Boolean, attribute: 'reverse-arrow' })
253
+ ], NrSiderElement.prototype, "reverseArrow", void 0);
254
+ __decorate([
255
+ property({ type: String, reflect: true })
256
+ ], NrSiderElement.prototype, "theme", void 0);
257
+ __decorate([
258
+ property({ type: String })
259
+ ], NrSiderElement.prototype, "trigger", void 0);
260
+ __decorate([
261
+ property({ type: String })
262
+ ], NrSiderElement.prototype, "width", void 0);
263
+ __decorate([
264
+ property({ type: String, attribute: 'zero-width-trigger-style' })
265
+ ], NrSiderElement.prototype, "zeroWidthTriggerStyle", void 0);
266
+ __decorate([
267
+ state()
268
+ ], NrSiderElement.prototype, "belowBreakpoint", void 0);
269
+ NrSiderElement = __decorate([
270
+ customElement('nr-sider')
271
+ ], NrSiderElement);
272
+ export { NrSiderElement };
273
+ //# sourceMappingURL=sider.component.js.map
@@ -0,0 +1,2 @@
1
+ export declare const siderStyles: import("lit").CSSResult;
2
+ //# sourceMappingURL=sider.style.d.ts.map
package/sider.style.js ADDED
@@ -0,0 +1,104 @@
1
+ import { css } from 'lit';
2
+ export const siderStyles = css `
3
+ :host {
4
+ display: block;
5
+ position: relative;
6
+ }
7
+
8
+ .nr-sider {
9
+ position: relative;
10
+ display: flex;
11
+ flex-direction: column;
12
+ min-width: 0;
13
+ background: var(--nuraly-layout-sider-background);
14
+ color: var(--nuraly-layout-sider-text);
15
+ border-right: 1px solid var(--nuraly-layout-sider-border);
16
+ transition: var(--nuraly-layout-sider-transition);
17
+ }
18
+
19
+ :host([theme='light']) .nr-sider {
20
+ background: var(--nuraly-layout-sider-light-background);
21
+ color: var(--nuraly-layout-sider-light-text);
22
+ border-right: 1px solid var(--nuraly-layout-sider-light-border);
23
+ }
24
+
25
+ .nr-sider-children {
26
+ flex: 1;
27
+ min-height: 0;
28
+ overflow: auto;
29
+ }
30
+
31
+ .nr-sider-trigger {
32
+ position: absolute;
33
+ bottom: 0;
34
+ left: 0;
35
+ right: 0;
36
+ height: var(--nuraly-layout-trigger-height);
37
+ display: flex;
38
+ align-items: center;
39
+ justify-content: center;
40
+ background: var(--nuraly-layout-trigger-background);
41
+ color: var(--nuraly-layout-trigger-text);
42
+ cursor: pointer;
43
+ transition: var(--nuraly-layout-transition);
44
+ border-top: 1px solid var(--nuraly-layout-trigger-border);
45
+ border-radius: var(--nuraly-layout-trigger-border-radius);
46
+ }
47
+
48
+ :host([theme='light']) .nr-sider-trigger {
49
+ background: var(--nuraly-layout-trigger-light-background);
50
+ color: var(--nuraly-layout-trigger-light-text);
51
+ border-top: 1px solid var(--nuraly-layout-trigger-light-border);
52
+ }
53
+
54
+ .nr-sider-trigger:hover {
55
+ background: var(--nuraly-layout-trigger-background-hover);
56
+ }
57
+
58
+ :host([theme='light']) .nr-sider-trigger:hover {
59
+ background: var(--nuraly-layout-trigger-light-background-hover);
60
+ }
61
+
62
+ .nr-sider-zero-width-trigger {
63
+ position: absolute;
64
+ top: 64px;
65
+ right: calc(-1 * var(--nuraly-layout-zero-trigger-width));
66
+ width: var(--nuraly-layout-zero-trigger-width);
67
+ height: var(--nuraly-layout-zero-trigger-height);
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ background: var(--nuraly-layout-zero-trigger-background);
72
+ color: var(--nuraly-layout-zero-trigger-text);
73
+ cursor: pointer;
74
+ transition: var(--nuraly-layout-transition);
75
+ border-radius: var(--nuraly-layout-zero-trigger-border-radius);
76
+ box-shadow: var(--nuraly-layout-zero-trigger-shadow);
77
+ z-index: 1;
78
+ }
79
+
80
+ :host([theme='light']) .nr-sider-zero-width-trigger {
81
+ background: var(--nuraly-layout-zero-trigger-background);
82
+ color: var(--nuraly-layout-zero-trigger-text);
83
+ }
84
+
85
+ .nr-sider-zero-width-trigger:hover {
86
+ background: var(--nuraly-layout-zero-trigger-background-hover);
87
+ }
88
+
89
+ .trigger-icon {
90
+ font-size: 16px;
91
+ line-height: 1;
92
+ }
93
+
94
+ .nr-sider-collapsed {
95
+ overflow: hidden;
96
+ }
97
+
98
+ .nr-sider-zero-width {
99
+ width: 0 !important;
100
+ min-width: 0 !important;
101
+ flex: 0 0 0 !important;
102
+ }
103
+ `;
104
+ //# sourceMappingURL=sider.style.js.map