mtrl 0.2.6 → 0.2.7

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 (147) hide show
  1. package/index.ts +18 -0
  2. package/package.json +1 -1
  3. package/src/components/badge/_styles.scss +117 -109
  4. package/src/components/badge/api.ts +57 -59
  5. package/src/components/badge/badge.ts +16 -2
  6. package/src/components/badge/config.ts +65 -11
  7. package/src/components/badge/constants.ts +22 -12
  8. package/src/components/badge/features.ts +44 -40
  9. package/src/components/badge/types.ts +42 -30
  10. package/src/components/bottom-app-bar/_styles.scss +103 -0
  11. package/src/components/bottom-app-bar/bottom-app-bar.ts +196 -0
  12. package/src/components/bottom-app-bar/config.ts +73 -0
  13. package/src/components/bottom-app-bar/index.ts +11 -0
  14. package/src/components/bottom-app-bar/types.ts +108 -0
  15. package/src/components/button/_styles.scss +0 -10
  16. package/src/components/button/api.ts +5 -0
  17. package/src/components/button/config.ts +5 -0
  18. package/src/components/button/types.ts +6 -0
  19. package/src/components/card/card.ts +13 -25
  20. package/src/components/card/config.ts +67 -22
  21. package/src/components/card/features.ts +3 -0
  22. package/src/components/card/types.ts +28 -0
  23. package/src/components/checkbox/_styles.scss +0 -2
  24. package/src/components/datepicker/_styles.scss +358 -0
  25. package/src/components/datepicker/api.ts +272 -0
  26. package/src/components/datepicker/config.ts +144 -0
  27. package/src/components/datepicker/constants.ts +98 -0
  28. package/src/components/datepicker/datepicker.ts +346 -0
  29. package/src/components/datepicker/index.ts +9 -0
  30. package/src/components/datepicker/render.ts +452 -0
  31. package/src/components/datepicker/types.ts +268 -0
  32. package/src/components/datepicker/utils.ts +290 -0
  33. package/src/components/dialog/_styles.scss +174 -128
  34. package/src/components/dialog/api.ts +48 -13
  35. package/src/components/dialog/config.ts +9 -5
  36. package/src/components/dialog/dialog.ts +6 -3
  37. package/src/components/dialog/features.ts +290 -130
  38. package/src/components/dialog/types.ts +7 -4
  39. package/src/components/divider/_styles.scss +57 -0
  40. package/src/components/divider/config.ts +81 -0
  41. package/src/components/divider/divider.ts +37 -0
  42. package/src/components/divider/features.ts +207 -0
  43. package/src/components/divider/index.ts +5 -0
  44. package/src/components/divider/types.ts +55 -0
  45. package/src/components/extended-fab/_styles.scss +267 -0
  46. package/src/components/extended-fab/api.ts +141 -0
  47. package/src/components/extended-fab/config.ts +108 -0
  48. package/src/components/extended-fab/constants.ts +36 -0
  49. package/src/components/extended-fab/extended-fab.ts +125 -0
  50. package/src/components/extended-fab/index.ts +4 -0
  51. package/src/components/extended-fab/types.ts +287 -0
  52. package/src/components/fab/_styles.scss +225 -0
  53. package/src/components/fab/api.ts +97 -0
  54. package/src/components/fab/config.ts +94 -0
  55. package/src/components/fab/constants.ts +41 -0
  56. package/src/components/fab/fab.ts +67 -0
  57. package/src/components/fab/index.ts +4 -0
  58. package/src/components/fab/types.ts +234 -0
  59. package/src/components/navigation/_styles.scss +1 -0
  60. package/src/components/navigation/api.ts +78 -50
  61. package/src/components/navigation/features/items.ts +280 -0
  62. package/src/components/navigation/nav-item.ts +72 -23
  63. package/src/components/navigation/navigation.ts +54 -2
  64. package/src/components/navigation/types.ts +210 -188
  65. package/src/components/search/_styles.scss +306 -0
  66. package/src/components/search/api.ts +203 -0
  67. package/src/components/search/config.ts +87 -0
  68. package/src/components/search/constants.ts +21 -0
  69. package/src/components/search/features/index.ts +4 -0
  70. package/src/components/search/features/search.ts +718 -0
  71. package/src/components/search/features/states.ts +165 -0
  72. package/src/components/search/features/structure.ts +198 -0
  73. package/src/components/search/index.ts +10 -0
  74. package/src/components/search/search.ts +52 -0
  75. package/src/components/search/types.ts +163 -0
  76. package/src/components/segmented-button/_styles.scss +117 -0
  77. package/src/components/segmented-button/config.ts +67 -0
  78. package/src/components/segmented-button/constants.ts +42 -0
  79. package/src/components/segmented-button/index.ts +4 -0
  80. package/src/components/segmented-button/segment.ts +155 -0
  81. package/src/components/segmented-button/segmented-button.ts +250 -0
  82. package/src/components/segmented-button/types.ts +219 -0
  83. package/src/components/slider/_styles.scss +83 -24
  84. package/src/components/slider/accessibility.md +5 -5
  85. package/src/components/slider/api.ts +41 -120
  86. package/src/components/slider/config.ts +51 -47
  87. package/src/components/slider/features/handlers.ts +495 -0
  88. package/src/components/slider/features/index.ts +1 -2
  89. package/src/components/slider/features/slider.ts +66 -84
  90. package/src/components/slider/features/states.ts +195 -0
  91. package/src/components/slider/features/structure.ts +136 -206
  92. package/src/components/slider/features/ui.ts +145 -206
  93. package/src/components/slider/index.ts +2 -11
  94. package/src/components/slider/slider.ts +9 -12
  95. package/src/components/slider/types.ts +39 -24
  96. package/src/components/switch/_styles.scss +0 -2
  97. package/src/components/tabs/_styles.scss +94 -32
  98. package/src/components/tabs/features.ts +4 -2
  99. package/src/components/tabs/indicator.ts +73 -13
  100. package/src/components/tabs/types.ts +10 -2
  101. package/src/components/timepicker/README.md +277 -0
  102. package/src/components/timepicker/_styles.scss +451 -0
  103. package/src/components/timepicker/api.ts +632 -0
  104. package/src/components/timepicker/clockdial.ts +482 -0
  105. package/src/components/timepicker/config.ts +130 -0
  106. package/src/components/timepicker/constants.ts +138 -0
  107. package/src/components/timepicker/index.ts +8 -0
  108. package/src/components/timepicker/render.ts +613 -0
  109. package/src/components/timepicker/timepicker.ts +117 -0
  110. package/src/components/timepicker/types.ts +336 -0
  111. package/src/components/timepicker/utils.ts +241 -0
  112. package/src/components/top-app-bar/_styles.scss +225 -0
  113. package/src/components/top-app-bar/config.ts +83 -0
  114. package/src/components/top-app-bar/index.ts +11 -0
  115. package/src/components/top-app-bar/top-app-bar.ts +316 -0
  116. package/src/components/top-app-bar/types.ts +140 -0
  117. package/src/core/build/_ripple.scss +6 -6
  118. package/src/core/build/ripple.ts +72 -95
  119. package/src/core/compose/features/icon.ts +3 -1
  120. package/src/core/compose/features/ripple.ts +4 -1
  121. package/src/core/compose/features/textlabel.ts +26 -2
  122. package/src/core/dom/create.ts +5 -0
  123. package/src/index.ts +9 -0
  124. package/src/styles/abstract/_theme.scss +9 -1
  125. package/src/styles/themes/_autumn.scss +21 -0
  126. package/src/styles/themes/_base-theme.scss +61 -0
  127. package/src/styles/themes/_baseline.scss +58 -0
  128. package/src/styles/themes/_bluekhaki.scss +125 -0
  129. package/src/styles/themes/_brownbeige.scss +125 -0
  130. package/src/styles/themes/_browngreen.scss +125 -0
  131. package/src/styles/themes/_forest.scss +6 -0
  132. package/src/styles/themes/_greenbeige.scss +125 -0
  133. package/src/styles/themes/_material.scss +125 -0
  134. package/src/styles/themes/_ocean.scss +6 -0
  135. package/src/styles/themes/_sageivory.scss +125 -0
  136. package/src/styles/themes/_spring.scss +6 -0
  137. package/src/styles/themes/_summer.scss +5 -0
  138. package/src/styles/themes/_sunset.scss +5 -0
  139. package/src/styles/themes/_tealcaramel.scss +125 -0
  140. package/src/styles/themes/_winter.scss +6 -0
  141. package/src/components/navigation/features/items.js +0 -192
  142. package/src/components/slider/features/appearance.ts +0 -94
  143. package/src/components/slider/features/disabled.ts +0 -68
  144. package/src/components/slider/features/events.ts +0 -164
  145. package/src/components/slider/features/interactions.ts +0 -396
  146. package/src/components/slider/features/keyboard.ts +0 -233
  147. package/src/core/collection/adapters/mongodb.js +0 -232
@@ -0,0 +1,225 @@
1
+ // src/components/top-app-bar/_styles.scss
2
+ @use 'sass:map';
3
+ @use '../../styles/abstract/base' as base;
4
+ @use '../../styles/abstract/variables' as v;
5
+ @use '../../styles/abstract/functions' as f;
6
+ @use '../../styles/abstract/mixins' as m;
7
+ @use '../../styles/abstract/theme' as t;
8
+
9
+ $component: '#{base.$prefix}-top-app-bar';
10
+
11
+ .#{$component} {
12
+ // Core Properties
13
+ position: absolute;
14
+ top: 0;
15
+ left: 0;
16
+ right: 0;
17
+ z-index: f.get-z-index('fixed');
18
+ display: flex;
19
+ align-items: center;
20
+ width: 100%;
21
+ background-color: t.color('surface');
22
+
23
+ // Default type (small) - 64dp height as per specs
24
+ height: 64px;
25
+ padding: 0 16px;
26
+
27
+ // Apply transition for scroll behavior
28
+ transition:
29
+ box-shadow 0.3s ease-in-out,
30
+ background-color 0.3s ease-in-out,
31
+ height 0.3s ease-in-out;
32
+
33
+ // Container for the headline
34
+ &-headline {
35
+ flex: 1;
36
+ display: flex;
37
+ align-items: center;
38
+ @include m.typography('title-large');
39
+ color: t.color('on-surface');
40
+ margin: 0;
41
+ padding: 0;
42
+ white-space: nowrap;
43
+ overflow: hidden;
44
+ text-overflow: ellipsis;
45
+ transition:
46
+ font-size 0.3s ease-in-out,
47
+ margin 0.3s ease-in-out,
48
+ padding 0.3s ease-in-out;
49
+ }
50
+
51
+ // Leading section (usually navigation icon)
52
+ &-leading {
53
+ display: flex;
54
+ align-items: center;
55
+ margin-right: 24px;
56
+ }
57
+
58
+ // Trailing section (usually action icons)
59
+ &-trailing {
60
+ display: flex;
61
+ align-items: center;
62
+ gap: 8px;
63
+ margin-left: auto;
64
+ }
65
+
66
+ // Center-aligned top app bar
67
+ &--center {
68
+ .#{$component}-headline {
69
+ position: absolute;
70
+ left: 50%;
71
+ transform: translateX(-50%);
72
+ text-align: center;
73
+ flex: 0;
74
+ }
75
+ }
76
+
77
+ // Medium top app bar - 112dp height
78
+ &--medium {
79
+ height: 112px;
80
+ flex-direction: column;
81
+ align-items: flex-start;
82
+ justify-content: space-between;
83
+ padding: 0;
84
+
85
+ .#{$component}-row {
86
+ display: flex;
87
+ align-items: center;
88
+ width: 100%;
89
+ padding: 0 16px;
90
+
91
+ &:first-child {
92
+ margin-top: 20px;
93
+ }
94
+ }
95
+
96
+ .#{$component}-headline {
97
+ margin-bottom: 24px;
98
+ margin-left: 16px;
99
+ @include m.typography('headline-small');
100
+ }
101
+ }
102
+
103
+ // Large top app bar - 152dp height
104
+ &--large {
105
+ height: 152px;
106
+ flex-direction: column;
107
+ align-items: flex-start;
108
+ justify-content: space-between;
109
+ padding: 0;
110
+
111
+ .#{$component}-row {
112
+ display: flex;
113
+ align-items: center;
114
+ width: 100%;
115
+ padding: 0 16px;
116
+
117
+ &:first-child {
118
+ margin-top: 20px;
119
+ }
120
+ }
121
+
122
+ .#{$component}-headline {
123
+ margin-bottom: 28px;
124
+ margin-left: 16px;
125
+ @include m.typography('headline-medium');
126
+ }
127
+ }
128
+
129
+ // States for on-scroll behavior
130
+ &--scrolled {
131
+ background-color: t.color('surface-container');
132
+ @include m.elevation(1);
133
+
134
+ // Compress medium and large variants to small on scroll if compressible
135
+ &.#{$component}--medium.#{$component}--compressible,
136
+ &.#{$component}--large.#{$component}--compressible {
137
+ height: 64px;
138
+ flex-direction: row;
139
+ align-items: center;
140
+ padding: 0 16px;
141
+
142
+ .#{$component}-row {
143
+ display: none;
144
+ }
145
+
146
+ .#{$component}-headline {
147
+ margin: 0;
148
+ @include m.typography('title-large');
149
+ }
150
+
151
+ // Fix for headline that is inside row in medium/large
152
+ .#{$component}-row:nth-child(2) {
153
+ display: flex;
154
+ flex: 1;
155
+ margin: 0;
156
+ padding: 0;
157
+ }
158
+ }
159
+ }
160
+
161
+ // RTL Support
162
+ [dir="rtl"] & {
163
+ .#{$component}-leading {
164
+ margin-right: 0;
165
+ margin-left: 24px;
166
+ }
167
+
168
+ .#{$component}-trailing {
169
+ margin-left: 0;
170
+ margin-right: auto;
171
+ }
172
+
173
+ &--medium,
174
+ &--large {
175
+ .#{$component}-headline {
176
+ margin-left: 0;
177
+ margin-right: 16px;
178
+ }
179
+ }
180
+
181
+ &--center {
182
+ .#{$component}-headline {
183
+ left: auto;
184
+ right: 50%;
185
+ transform: translateX(50%);
186
+ }
187
+ }
188
+ }
189
+
190
+ // Mobile screen adjustments
191
+ @media (max-width: map.get(v.$breakpoints, 'sm')) {
192
+ // Reduce side padding slightly on small screens
193
+ padding: 0 12px;
194
+
195
+ .#{$component}-leading {
196
+ margin-right: 16px;
197
+ }
198
+
199
+ .#{$component}-trailing {
200
+ gap: 4px;
201
+ }
202
+
203
+ // Make icon buttons slightly smaller
204
+ .#{$component}-leading,
205
+ .#{$component}-trailing {
206
+ button {
207
+ padding: 8px;
208
+ }
209
+ }
210
+ }
211
+
212
+ // Reduced motion support
213
+ @include m.reduced-motion {
214
+ transition-duration: 0.01ms;
215
+
216
+ .#{$component}-headline {
217
+ transition-duration: 0.01ms;
218
+ }
219
+ }
220
+
221
+ // High contrast mode support
222
+ @include m.high-contrast {
223
+ border-bottom: 1px solid currentColor;
224
+ }
225
+ }
@@ -0,0 +1,83 @@
1
+ // src/components/top-app-bar/config.ts
2
+ /**
3
+ * @module components/top-app-bar
4
+ * @description Configuration for top app bar component
5
+ */
6
+
7
+ import { createComponentConfig, BaseComponentConfig } from '../../core/config/component-config';
8
+ import { PREFIX } from '../../core/config';
9
+
10
+ /**
11
+ * Top App Bar types
12
+ */
13
+ export type TopAppBarType = 'small' | 'medium' | 'large' | 'center';
14
+
15
+ /**
16
+ * Configuration options for top app bar
17
+ */
18
+ export interface TopAppBarConfig extends BaseComponentConfig {
19
+ /**
20
+ * Element to use for the container
21
+ * @default 'header'
22
+ */
23
+ tag?: string;
24
+
25
+ /**
26
+ * Type of top app bar to display
27
+ * @default 'small'
28
+ */
29
+ type?: TopAppBarType;
30
+
31
+ /**
32
+ * Title text to display in the app bar
33
+ */
34
+ title?: string;
35
+
36
+ /**
37
+ * Whether to enable scrolling behavior
38
+ * @default true
39
+ */
40
+ scrollable?: boolean;
41
+
42
+ /**
43
+ * Whether to compress medium/large variants to small on scroll
44
+ * @default true
45
+ */
46
+ compressible?: boolean;
47
+
48
+ /**
49
+ * Scroll threshold in pixels to trigger the scrolled state
50
+ * @default 4
51
+ */
52
+ scrollThreshold?: number;
53
+
54
+ /**
55
+ * Additional CSS classes to apply
56
+ */
57
+ class?: string;
58
+
59
+ /**
60
+ * Optional callback when scrolling changes the bar appearance
61
+ */
62
+ onScroll?: (scrolled: boolean) => void;
63
+ }
64
+
65
+ /**
66
+ * Default configuration for top app bar
67
+ */
68
+ export const defaultConfig: Partial<TopAppBarConfig> = {
69
+ tag: 'header',
70
+ type: 'small',
71
+ scrollable: true,
72
+ compressible: true,
73
+ scrollThreshold: 4
74
+ };
75
+
76
+ /**
77
+ * Creates the configuration for a top app bar component
78
+ *
79
+ * @param {TopAppBarConfig} config - User provided configuration
80
+ * @returns {TopAppBarConfig} Complete configuration with defaults applied
81
+ */
82
+ export const createConfig = (config: TopAppBarConfig = {} as TopAppBarConfig): TopAppBarConfig =>
83
+ createComponentConfig(defaultConfig, config, 'top-app-bar') as TopAppBarConfig;
@@ -0,0 +1,11 @@
1
+ // src/components/top-app-bar/index.ts
2
+ /**
3
+ * @module components/top-app-bar
4
+ * @description Top app bar component for application headers
5
+ */
6
+
7
+ import { createTopAppBar } from './top-app-bar';
8
+
9
+ export default createTopAppBar;
10
+ export { createTopAppBar };
11
+ export type { TopAppBarConfig, TopAppBarType } from './config';
@@ -0,0 +1,316 @@
1
+ // src/components/top-app-bar/top-app-bar.ts
2
+ /**
3
+ * @module components/top-app-bar
4
+ * @description Top app bar implementation
5
+ */
6
+
7
+ import {
8
+ createBase,
9
+ withElement,
10
+ withEvents,
11
+ withLifecycle,
12
+ ElementComponent,
13
+ BaseComponent
14
+ } from '../../core/compose';
15
+
16
+ import { createConfig, TopAppBarConfig, TopAppBarType } from './config';
17
+
18
+ /**
19
+ * Top app bar component interface
20
+ */
21
+ export interface TopAppBar extends ElementComponent {
22
+ /**
23
+ * Sets the title of the top app bar
24
+ * @param {string} title - Title text
25
+ * @returns {TopAppBar} TopAppBar instance for chaining
26
+ */
27
+ setTitle: (title: string) => TopAppBar;
28
+
29
+ /**
30
+ * Gets the current title
31
+ * @returns {string} Current title text
32
+ */
33
+ getTitle: () => string;
34
+
35
+ /**
36
+ * Adds a leading navigation icon or element
37
+ * @param {HTMLElement} element - Element to add to the leading section
38
+ * @returns {TopAppBar} TopAppBar instance for chaining
39
+ */
40
+ addLeadingElement: (element: HTMLElement) => TopAppBar;
41
+
42
+ /**
43
+ * Adds a trailing action icon or element
44
+ * @param {HTMLElement} element - Element to add to the trailing section
45
+ * @returns {TopAppBar} TopAppBar instance for chaining
46
+ */
47
+ addTrailingElement: (element: HTMLElement) => TopAppBar;
48
+
49
+ /**
50
+ * Changes the top app bar type
51
+ * @param {TopAppBarType} type - New app bar type
52
+ * @returns {TopAppBar} TopAppBar instance for chaining
53
+ */
54
+ setType: (type: TopAppBarType) => TopAppBar;
55
+
56
+ /**
57
+ * Manually sets the scrolled state
58
+ * @param {boolean} scrolled - Whether to show the scrolled state
59
+ * @returns {TopAppBar} TopAppBar instance for chaining
60
+ */
61
+ setScrollState: (scrolled: boolean) => TopAppBar;
62
+
63
+ /**
64
+ * Gets the headline element
65
+ * @returns {HTMLElement} Headline element
66
+ */
67
+ getHeadlineElement: () => HTMLElement;
68
+
69
+ /**
70
+ * Gets the leading container element
71
+ * @returns {HTMLElement} Leading container element
72
+ */
73
+ getLeadingContainer: () => HTMLElement;
74
+
75
+ /**
76
+ * Gets the trailing container element
77
+ * @returns {HTMLElement} Trailing container element
78
+ */
79
+ getTrailingContainer: () => HTMLElement;
80
+ }
81
+
82
+ /**
83
+ * Creates a top app bar component
84
+ *
85
+ * @param {TopAppBarConfig} config - Configuration options
86
+ * @returns {TopAppBar} Top app bar component instance
87
+ */
88
+ export const createTopAppBar = (config: TopAppBarConfig = {}): TopAppBar => {
89
+ // Process configuration with defaults
90
+ const componentConfig = createConfig(config);
91
+
92
+ // Create base component
93
+ const component = createBase(componentConfig);
94
+
95
+ // Create containers for the top app bar structure
96
+ const createContainers = () => {
97
+ // Leading section container
98
+ const leadingContainer = document.createElement('div');
99
+ leadingContainer.className = `${component.getClass('top-app-bar')}-leading`;
100
+
101
+ // Headline element
102
+ const headlineElement = document.createElement('h1');
103
+ headlineElement.className = `${component.getClass('top-app-bar')}-headline`;
104
+ if (componentConfig.title) {
105
+ headlineElement.textContent = componentConfig.title;
106
+ }
107
+
108
+ // Trailing section container
109
+ const trailingContainer = document.createElement('div');
110
+ trailingContainer.className = `${component.getClass('top-app-bar')}-trailing`;
111
+
112
+ return { leadingContainer, headlineElement, trailingContainer };
113
+ };
114
+
115
+ // Create the main containers
116
+ const { leadingContainer, headlineElement, trailingContainer } = createContainers();
117
+
118
+ // Determine initial classes based on type
119
+ const getInitialClasses = () => {
120
+ const classes = [componentConfig.class];
121
+
122
+ // Add type class if not the default 'small' type
123
+ if (componentConfig.type !== 'small') {
124
+ classes.push(`${component.getClass('top-app-bar')}--${componentConfig.type}`);
125
+ }
126
+
127
+ // Add compressible class if enabled and type is medium or large
128
+ if (componentConfig.compressible &&
129
+ (componentConfig.type === 'medium' || componentConfig.type === 'large')) {
130
+ classes.push(`${component.getClass('top-app-bar')}--compressible`);
131
+ }
132
+
133
+ return classes.filter(Boolean);
134
+ };
135
+
136
+ // Apply Element enhancer
137
+ const enhancedComponent = withElement({
138
+ tag: componentConfig.tag,
139
+ componentName: 'top-app-bar',
140
+ className: getInitialClasses(),
141
+ attrs: {
142
+ role: 'banner',
143
+ 'aria-label': 'Top app bar'
144
+ },
145
+ interactive: true
146
+ })(component);
147
+
148
+ // Apply events enhancer for component events
149
+ const withEventsComponent = withEvents()(enhancedComponent);
150
+
151
+ // Apply lifecycle enhancer for cleanup
152
+ const withLifecycleComponent = withLifecycle()(withEventsComponent);
153
+
154
+ // Create the DOM structure based on the type
155
+ const setupDomStructure = () => {
156
+ if (componentConfig.type === 'medium' || componentConfig.type === 'large') {
157
+ // For medium and large, create rows
158
+ const topRow = document.createElement('div');
159
+ topRow.className = `${component.getClass('top-app-bar')}-row`;
160
+ topRow.appendChild(leadingContainer);
161
+ topRow.appendChild(trailingContainer);
162
+
163
+ const bottomRow = document.createElement('div');
164
+ bottomRow.className = `${component.getClass('top-app-bar')}-row`;
165
+ bottomRow.appendChild(headlineElement);
166
+
167
+ withLifecycleComponent.element.appendChild(topRow);
168
+ withLifecycleComponent.element.appendChild(bottomRow);
169
+ } else {
170
+ // For small and center-aligned
171
+ withLifecycleComponent.element.appendChild(leadingContainer);
172
+ withLifecycleComponent.element.appendChild(headlineElement);
173
+ withLifecycleComponent.element.appendChild(trailingContainer);
174
+ }
175
+ };
176
+
177
+ // Set up the initial DOM structure
178
+ setupDomStructure();
179
+
180
+ // Track scrolled state
181
+ let isScrolled = false;
182
+
183
+ // Handle scrolling behavior if enabled
184
+ if (componentConfig.scrollable) {
185
+ const handleScroll = () => {
186
+ const shouldBeScrolled = window.scrollY > componentConfig.scrollThreshold;
187
+
188
+ if (isScrolled !== shouldBeScrolled) {
189
+ isScrolled = shouldBeScrolled;
190
+
191
+ // Toggle scrolled class
192
+ if (isScrolled) {
193
+ withLifecycleComponent.element.classList.add(`${component.getClass('top-app-bar')}--scrolled`);
194
+ } else {
195
+ withLifecycleComponent.element.classList.remove(`${component.getClass('top-app-bar')}--scrolled`);
196
+ }
197
+
198
+ // Call the onScroll callback if provided
199
+ componentConfig.onScroll?.(isScrolled);
200
+ }
201
+ };
202
+
203
+ // Add scroll event listener
204
+ window.addEventListener('scroll', handleScroll, { passive: true });
205
+
206
+ // Initial check
207
+ handleScroll();
208
+
209
+ // Clean up event listener on destroy
210
+ const originalDestroy = withLifecycleComponent.lifecycle.destroy;
211
+ withLifecycleComponent.lifecycle.destroy = () => {
212
+ window.removeEventListener('scroll', handleScroll);
213
+ originalDestroy();
214
+ };
215
+ }
216
+
217
+ // Reorganize the DOM for the given type
218
+ const reorganizeDom = (type: TopAppBarType) => {
219
+ // Clear existing content
220
+ while (withLifecycleComponent.element.firstChild) {
221
+ withLifecycleComponent.element.removeChild(withLifecycleComponent.element.firstChild);
222
+ }
223
+
224
+ // Update component type class
225
+ ['small', 'medium', 'large', 'center'].forEach(t => {
226
+ withLifecycleComponent.element.classList.remove(`${component.getClass('top-app-bar')}--${t}`);
227
+ });
228
+
229
+ if (type !== 'small') {
230
+ withLifecycleComponent.element.classList.add(`${component.getClass('top-app-bar')}--${type}`);
231
+ }
232
+
233
+ // Update compressible class
234
+ withLifecycleComponent.element.classList.toggle(
235
+ `${component.getClass('top-app-bar')}--compressible`,
236
+ componentConfig.compressible && (type === 'medium' || type === 'large')
237
+ );
238
+
239
+ // Rebuild the DOM structure
240
+ if (type === 'medium' || type === 'large') {
241
+ // For medium and large, create rows
242
+ const topRow = document.createElement('div');
243
+ topRow.className = `${component.getClass('top-app-bar')}-row`;
244
+ topRow.appendChild(leadingContainer);
245
+ topRow.appendChild(trailingContainer);
246
+
247
+ const bottomRow = document.createElement('div');
248
+ bottomRow.className = `${component.getClass('top-app-bar')}-row`;
249
+ bottomRow.appendChild(headlineElement);
250
+
251
+ withLifecycleComponent.element.appendChild(topRow);
252
+ withLifecycleComponent.element.appendChild(bottomRow);
253
+ } else {
254
+ // For small and center-aligned
255
+ withLifecycleComponent.element.appendChild(leadingContainer);
256
+ withLifecycleComponent.element.appendChild(headlineElement);
257
+ withLifecycleComponent.element.appendChild(trailingContainer);
258
+ }
259
+ };
260
+
261
+ // Create the top app bar interface
262
+ const topAppBar: TopAppBar = {
263
+ ...withLifecycleComponent,
264
+
265
+ setTitle(title: string) {
266
+ headlineElement.textContent = title;
267
+ return this;
268
+ },
269
+
270
+ getTitle() {
271
+ return headlineElement.textContent || '';
272
+ },
273
+
274
+ addLeadingElement(element: HTMLElement) {
275
+ leadingContainer.appendChild(element);
276
+ return this;
277
+ },
278
+
279
+ addTrailingElement(element: HTMLElement) {
280
+ trailingContainer.appendChild(element);
281
+ return this;
282
+ },
283
+
284
+ setType(type: TopAppBarType) {
285
+ componentConfig.type = type;
286
+ reorganizeDom(type);
287
+ return this;
288
+ },
289
+
290
+ setScrollState(scrolled: boolean) {
291
+ isScrolled = scrolled;
292
+
293
+ if (scrolled) {
294
+ this.element.classList.add(`${component.getClass('top-app-bar')}--scrolled`);
295
+ } else {
296
+ this.element.classList.remove(`${component.getClass('top-app-bar')}--scrolled`);
297
+ }
298
+
299
+ return this;
300
+ },
301
+
302
+ getHeadlineElement() {
303
+ return headlineElement;
304
+ },
305
+
306
+ getLeadingContainer() {
307
+ return leadingContainer;
308
+ },
309
+
310
+ getTrailingContainer() {
311
+ return trailingContainer;
312
+ }
313
+ };
314
+
315
+ return topAppBar;
316
+ };