@chromvoid/uikit 0.1.0

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 (246) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +96 -0
  3. package/dist/components/cv-accordion-item.d.ts +69 -0
  4. package/dist/components/cv-accordion-item.js +176 -0
  5. package/dist/components/cv-accordion.d.ts +79 -0
  6. package/dist/components/cv-accordion.js +310 -0
  7. package/dist/components/cv-alert-dialog.d.ts +86 -0
  8. package/dist/components/cv-alert-dialog.js +393 -0
  9. package/dist/components/cv-alert.d.ts +48 -0
  10. package/dist/components/cv-alert.js +156 -0
  11. package/dist/components/cv-badge.d.ts +56 -0
  12. package/dist/components/cv-badge.js +280 -0
  13. package/dist/components/cv-breadcrumb-item.d.ts +35 -0
  14. package/dist/components/cv-breadcrumb-item.js +64 -0
  15. package/dist/components/cv-breadcrumb.d.ts +39 -0
  16. package/dist/components/cv-breadcrumb.js +160 -0
  17. package/dist/components/cv-button.d.ts +83 -0
  18. package/dist/components/cv-button.js +541 -0
  19. package/dist/components/cv-callout.d.ts +32 -0
  20. package/dist/components/cv-callout.js +221 -0
  21. package/dist/components/cv-card.d.ts +48 -0
  22. package/dist/components/cv-card.js +269 -0
  23. package/dist/components/cv-carousel-slide.d.ts +25 -0
  24. package/dist/components/cv-carousel-slide.js +51 -0
  25. package/dist/components/cv-carousel.d.ts +96 -0
  26. package/dist/components/cv-carousel.js +457 -0
  27. package/dist/components/cv-checkbox.d.ts +84 -0
  28. package/dist/components/cv-checkbox.js +274 -0
  29. package/dist/components/cv-combobox-group.d.ts +15 -0
  30. package/dist/components/cv-combobox-group.js +34 -0
  31. package/dist/components/cv-combobox-option.d.ts +30 -0
  32. package/dist/components/cv-combobox-option.js +66 -0
  33. package/dist/components/cv-combobox.d.ts +135 -0
  34. package/dist/components/cv-combobox.js +834 -0
  35. package/dist/components/cv-command-item.d.ts +30 -0
  36. package/dist/components/cv-command-item.js +68 -0
  37. package/dist/components/cv-command-palette.d.ts +105 -0
  38. package/dist/components/cv-command-palette.js +578 -0
  39. package/dist/components/cv-context-menu.d.ts +98 -0
  40. package/dist/components/cv-context-menu.js +515 -0
  41. package/dist/components/cv-copy-button.d.ts +61 -0
  42. package/dist/components/cv-copy-button.js +318 -0
  43. package/dist/components/cv-date-picker.d.ts +161 -0
  44. package/dist/components/cv-date-picker.js +803 -0
  45. package/dist/components/cv-dialog.d.ts +89 -0
  46. package/dist/components/cv-dialog.js +459 -0
  47. package/dist/components/cv-disclosure.d.ts +57 -0
  48. package/dist/components/cv-disclosure.js +241 -0
  49. package/dist/components/cv-drawer.d.ts +102 -0
  50. package/dist/components/cv-drawer.js +595 -0
  51. package/dist/components/cv-feed-article.d.ts +26 -0
  52. package/dist/components/cv-feed-article.js +52 -0
  53. package/dist/components/cv-feed.d.ts +62 -0
  54. package/dist/components/cv-feed.js +310 -0
  55. package/dist/components/cv-grid-cell.d.ts +30 -0
  56. package/dist/components/cv-grid-cell.js +57 -0
  57. package/dist/components/cv-grid-column.d.ts +30 -0
  58. package/dist/components/cv-grid-column.js +43 -0
  59. package/dist/components/cv-grid-row.d.ts +30 -0
  60. package/dist/components/cv-grid-row.js +42 -0
  61. package/dist/components/cv-grid.d.ts +119 -0
  62. package/dist/components/cv-grid.js +567 -0
  63. package/dist/components/cv-icon.d.ts +57 -0
  64. package/dist/components/cv-icon.js +352 -0
  65. package/dist/components/cv-input.d.ts +127 -0
  66. package/dist/components/cv-input.js +482 -0
  67. package/dist/components/cv-landmark.d.ts +32 -0
  68. package/dist/components/cv-landmark.js +62 -0
  69. package/dist/components/cv-link.d.ts +22 -0
  70. package/dist/components/cv-link.js +99 -0
  71. package/dist/components/cv-listbox-group.d.ts +15 -0
  72. package/dist/components/cv-listbox-group.js +42 -0
  73. package/dist/components/cv-listbox.d.ts +81 -0
  74. package/dist/components/cv-listbox.js +388 -0
  75. package/dist/components/cv-menu-button.d.ts +118 -0
  76. package/dist/components/cv-menu-button.js +822 -0
  77. package/dist/components/cv-menu-group.d.ts +20 -0
  78. package/dist/components/cv-menu-group.js +48 -0
  79. package/dist/components/cv-menu-item.d.ts +52 -0
  80. package/dist/components/cv-menu-item.js +105 -0
  81. package/dist/components/cv-menu.d.ts +62 -0
  82. package/dist/components/cv-menu.js +414 -0
  83. package/dist/components/cv-meter.d.ts +66 -0
  84. package/dist/components/cv-meter.js +154 -0
  85. package/dist/components/cv-number.d.ts +139 -0
  86. package/dist/components/cv-number.js +553 -0
  87. package/dist/components/cv-option.d.ts +30 -0
  88. package/dist/components/cv-option.js +84 -0
  89. package/dist/components/cv-popover.d.ts +87 -0
  90. package/dist/components/cv-popover.js +373 -0
  91. package/dist/components/cv-progress-ring.d.ts +45 -0
  92. package/dist/components/cv-progress-ring.js +169 -0
  93. package/dist/components/cv-progress.d.ts +45 -0
  94. package/dist/components/cv-progress.js +148 -0
  95. package/dist/components/cv-radio-group.d.ts +79 -0
  96. package/dist/components/cv-radio-group.js +398 -0
  97. package/dist/components/cv-radio.d.ts +36 -0
  98. package/dist/components/cv-radio.js +123 -0
  99. package/dist/components/cv-select-group.d.ts +15 -0
  100. package/dist/components/cv-select-group.js +44 -0
  101. package/dist/components/cv-select-option.d.ts +30 -0
  102. package/dist/components/cv-select-option.js +66 -0
  103. package/dist/components/cv-select.d.ts +128 -0
  104. package/dist/components/cv-select.js +666 -0
  105. package/dist/components/cv-sidebar-item.d.ts +26 -0
  106. package/dist/components/cv-sidebar-item.js +142 -0
  107. package/dist/components/cv-sidebar.d.ts +171 -0
  108. package/dist/components/cv-sidebar.js +767 -0
  109. package/dist/components/cv-slider-multi-thumb.d.ts +73 -0
  110. package/dist/components/cv-slider-multi-thumb.js +374 -0
  111. package/dist/components/cv-slider.d.ts +84 -0
  112. package/dist/components/cv-slider.js +328 -0
  113. package/dist/components/cv-spinbutton.d.ts +121 -0
  114. package/dist/components/cv-spinbutton.js +486 -0
  115. package/dist/components/cv-spinner.d.ts +18 -0
  116. package/dist/components/cv-spinner.js +95 -0
  117. package/dist/components/cv-switch.d.ts +81 -0
  118. package/dist/components/cv-switch.js +285 -0
  119. package/dist/components/cv-tab-panel.d.ts +20 -0
  120. package/dist/components/cv-tab-panel.js +37 -0
  121. package/dist/components/cv-tab.d.ts +40 -0
  122. package/dist/components/cv-tab.js +132 -0
  123. package/dist/components/cv-table-cell.d.ts +31 -0
  124. package/dist/components/cv-table-cell.js +49 -0
  125. package/dist/components/cv-table-column.d.ts +37 -0
  126. package/dist/components/cv-table-column.js +63 -0
  127. package/dist/components/cv-table-row.d.ts +30 -0
  128. package/dist/components/cv-table-row.js +45 -0
  129. package/dist/components/cv-table.d.ts +147 -0
  130. package/dist/components/cv-table.js +607 -0
  131. package/dist/components/cv-tabs.d.ts +70 -0
  132. package/dist/components/cv-tabs.js +524 -0
  133. package/dist/components/cv-textarea.d.ts +108 -0
  134. package/dist/components/cv-textarea.js +328 -0
  135. package/dist/components/cv-toast-region.d.ts +39 -0
  136. package/dist/components/cv-toast-region.js +162 -0
  137. package/dist/components/cv-toast.d.ts +67 -0
  138. package/dist/components/cv-toast.js +315 -0
  139. package/dist/components/cv-toolbar-item.d.ts +25 -0
  140. package/dist/components/cv-toolbar-item.js +72 -0
  141. package/dist/components/cv-toolbar-separator.d.ts +25 -0
  142. package/dist/components/cv-toolbar-separator.js +45 -0
  143. package/dist/components/cv-toolbar.d.ts +63 -0
  144. package/dist/components/cv-toolbar.js +295 -0
  145. package/dist/components/cv-tooltip.d.ts +83 -0
  146. package/dist/components/cv-tooltip.js +455 -0
  147. package/dist/components/cv-treegrid-cell.d.ts +30 -0
  148. package/dist/components/cv-treegrid-cell.js +57 -0
  149. package/dist/components/cv-treegrid-column.d.ts +37 -0
  150. package/dist/components/cv-treegrid-column.js +53 -0
  151. package/dist/components/cv-treegrid-row.d.ts +55 -0
  152. package/dist/components/cv-treegrid-row.js +90 -0
  153. package/dist/components/cv-treegrid.d.ts +96 -0
  154. package/dist/components/cv-treegrid.js +632 -0
  155. package/dist/components/cv-treeitem.d.ts +58 -0
  156. package/dist/components/cv-treeitem.js +144 -0
  157. package/dist/components/cv-treeview.d.ts +70 -0
  158. package/dist/components/cv-treeview.js +396 -0
  159. package/dist/components/cv-window-splitter.d.ts +79 -0
  160. package/dist/components/cv-window-splitter.js +316 -0
  161. package/dist/components/index.d.ts +94 -0
  162. package/dist/components/index.js +79 -0
  163. package/dist/dialog/create-dialog-controller.d.ts +31 -0
  164. package/dist/dialog/create-dialog-controller.js +320 -0
  165. package/dist/dialog/index.d.ts +2 -0
  166. package/dist/dialog/index.js +1 -0
  167. package/dist/form-associated/FormAssociatedReatomElement.d.ts +25 -0
  168. package/dist/form-associated/FormAssociatedReatomElement.js +70 -0
  169. package/dist/form-associated/withFormAssociated.d.ts +5 -0
  170. package/dist/form-associated/withFormAssociated.js +1 -0
  171. package/dist/index.d.ts +10 -0
  172. package/dist/index.js +9 -0
  173. package/dist/reatom-lit/ReatomLitElement.d.ts +27 -0
  174. package/dist/reatom-lit/ReatomLitElement.js +118 -0
  175. package/dist/reatom-lit/html.d.ts +4 -0
  176. package/dist/reatom-lit/html.js +10 -0
  177. package/dist/reatom-lit/index.d.ts +4 -0
  178. package/dist/reatom-lit/index.js +4 -0
  179. package/dist/reatom-lit/watch.d.ts +15 -0
  180. package/dist/reatom-lit/watch.js +40 -0
  181. package/dist/reatom-lit/withReatomElement.d.ts +4 -0
  182. package/dist/reatom-lit/withReatomElement.js +57 -0
  183. package/dist/register.d.ts +1 -0
  184. package/dist/register.js +84 -0
  185. package/dist/styles/component-styles.d.ts +4 -0
  186. package/dist/styles/component-styles.js +78 -0
  187. package/dist/theme/cv-theme-provider.d.ts +32 -0
  188. package/dist/theme/cv-theme-provider.js +110 -0
  189. package/dist/theme/index.d.ts +4 -0
  190. package/dist/theme/index.js +2 -0
  191. package/dist/theme/theme-engine.d.ts +4 -0
  192. package/dist/theme/theme-engine.js +67 -0
  193. package/dist/theme/tokens.css +265 -0
  194. package/dist/theme/types.d.ts +7 -0
  195. package/dist/theme/types.js +1 -0
  196. package/dist/toast/create-toast-controller.d.ts +12 -0
  197. package/dist/toast/create-toast-controller.js +12 -0
  198. package/dist/toast/index.d.ts +2 -0
  199. package/dist/toast/index.js +1 -0
  200. package/package.json +146 -0
  201. package/specs/_template.md +110 -0
  202. package/specs/components/accordion.md +207 -0
  203. package/specs/components/alert.md +83 -0
  204. package/specs/components/badge.md +183 -0
  205. package/specs/components/breadcrumb.md +152 -0
  206. package/specs/components/button.md +227 -0
  207. package/specs/components/callout.md +153 -0
  208. package/specs/components/card.md +192 -0
  209. package/specs/components/carousel.md +232 -0
  210. package/specs/components/checkbox.md +141 -0
  211. package/specs/components/combobox.md +427 -0
  212. package/specs/components/context-menu.md +375 -0
  213. package/specs/components/copy-button.md +236 -0
  214. package/specs/components/date-picker.md +290 -0
  215. package/specs/components/dialog.md +184 -0
  216. package/specs/components/disclosure.md +151 -0
  217. package/specs/components/drawer.md +216 -0
  218. package/specs/components/feed.md +266 -0
  219. package/specs/components/grid.md +423 -0
  220. package/specs/components/input.md +237 -0
  221. package/specs/components/landmark.md +92 -0
  222. package/specs/components/link.md +117 -0
  223. package/specs/components/listbox.md +327 -0
  224. package/specs/components/menu.md +508 -0
  225. package/specs/components/meter.md +148 -0
  226. package/specs/components/number.md +268 -0
  227. package/specs/components/option.md +167 -0
  228. package/specs/components/popover.md +207 -0
  229. package/specs/components/progress-ring.md +134 -0
  230. package/specs/components/progress.md +110 -0
  231. package/specs/components/radio.md +208 -0
  232. package/specs/components/select.md +305 -0
  233. package/specs/components/sidebar.md +204 -0
  234. package/specs/components/spinbutton.md +157 -0
  235. package/specs/components/spinner.md +83 -0
  236. package/specs/components/switch.md +145 -0
  237. package/specs/components/table.md +372 -0
  238. package/specs/components/tabs.md +242 -0
  239. package/specs/components/textarea.md +166 -0
  240. package/specs/components/theme.md +364 -0
  241. package/specs/components/toast.md +198 -0
  242. package/specs/components/toolbar.md +258 -0
  243. package/specs/components/tooltip.md +152 -0
  244. package/specs/components/treegrid.md +363 -0
  245. package/specs/components/treeview.md +263 -0
  246. package/specs/components/window-splitter.md +225 -0
@@ -0,0 +1,62 @@
1
+ import type { PropertyValues } from 'lit';
2
+ import { ReatomLitElement } from '../reatom-lit/ReatomLitElement.js';
3
+ export type CVFeedLoadMoreEvent = CustomEvent<Record<string, never>>;
4
+ export type CVFeedLoadNewerEvent = CustomEvent<Record<string, never>>;
5
+ export type CVFeedExitAfterEvent = CustomEvent<Record<string, never>>;
6
+ export type CVFeedExitBeforeEvent = CustomEvent<Record<string, never>>;
7
+ export interface CVFeedEventMap {
8
+ 'cv-load-more': CVFeedLoadMoreEvent;
9
+ 'cv-load-newer': CVFeedLoadNewerEvent;
10
+ 'cv-exit-after': CVFeedExitAfterEvent;
11
+ 'cv-exit-before': CVFeedExitBeforeEvent;
12
+ }
13
+ export declare class CVFeed extends ReatomLitElement {
14
+ static elementName: string;
15
+ static get properties(): {
16
+ label: {
17
+ type: StringConstructor;
18
+ reflect: boolean;
19
+ };
20
+ busy: {
21
+ type: BooleanConstructor;
22
+ reflect: boolean;
23
+ };
24
+ loading: {
25
+ type: BooleanConstructor;
26
+ reflect: boolean;
27
+ };
28
+ empty: {
29
+ type: BooleanConstructor;
30
+ reflect: boolean;
31
+ };
32
+ error: {
33
+ type: BooleanConstructor;
34
+ reflect: boolean;
35
+ };
36
+ };
37
+ label: string;
38
+ busy: boolean;
39
+ loading: boolean;
40
+ empty: boolean;
41
+ error: boolean;
42
+ private readonly idBase;
43
+ private model;
44
+ private observer;
45
+ constructor();
46
+ static styles: import("lit").CSSResult[];
47
+ static define(): void;
48
+ connectedCallback(): void;
49
+ disconnectedCallback(): void;
50
+ willUpdate(changedProperties: PropertyValues): void;
51
+ updated(changedProperties: PropertyValues): void;
52
+ private createModel;
53
+ private getArticleElements;
54
+ private rebuildModel;
55
+ private syncArticleElements;
56
+ private syncHostAttributes;
57
+ private setupObserver;
58
+ private destroyObserver;
59
+ private handleKeyDown;
60
+ private handleSlotChange;
61
+ protected render(): import("lit").TemplateResult<1>;
62
+ }
@@ -0,0 +1,310 @@
1
+ import { createFeed, } from '@chromvoid/headless-ui/feed';
2
+ import { css, html, nothing } from 'lit';
3
+ import { ReatomLitElement } from '../reatom-lit/ReatomLitElement.js';
4
+ let cvFeedNonce = 0;
5
+ export class CVFeed extends ReatomLitElement {
6
+ static elementName = 'cv-feed';
7
+ static get properties() {
8
+ return {
9
+ label: { type: String, reflect: true },
10
+ busy: { type: Boolean, reflect: true },
11
+ loading: { type: Boolean, reflect: true },
12
+ empty: { type: Boolean, reflect: true },
13
+ error: { type: Boolean, reflect: true },
14
+ };
15
+ }
16
+ idBase = `cv-feed-${++cvFeedNonce}`;
17
+ model;
18
+ observer = null;
19
+ constructor() {
20
+ super();
21
+ this.label = '';
22
+ this.busy = false;
23
+ this.loading = false;
24
+ this.empty = true;
25
+ this.error = false;
26
+ this.model = this.createModel([]);
27
+ }
28
+ static styles = [
29
+ css `
30
+ :host {
31
+ display: block;
32
+ }
33
+
34
+ [part='base'] {
35
+ display: flex;
36
+ flex-direction: column;
37
+ gap: var(--cv-feed-gap, var(--cv-space-3, 12px));
38
+ padding-block: var(--cv-feed-padding-block, var(--cv-space-3, 12px));
39
+ padding-inline: var(--cv-feed-padding-inline, 0);
40
+ }
41
+
42
+ [part='sentinel-top'],
43
+ [part='sentinel-bottom'] {
44
+ height: var(--cv-feed-sentinel-height, 1px);
45
+ overflow: hidden;
46
+ }
47
+
48
+ [part='loading-indicator'] {
49
+ display: flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ min-height: var(--cv-feed-loading-min-height, 48px);
53
+ }
54
+
55
+ :host([busy]) [part='base'] {
56
+ opacity: 0.8;
57
+ }
58
+
59
+ :host([empty]) [part='base'] {
60
+ min-height: 0;
61
+ }
62
+
63
+ :host([error]) [part='base'] {
64
+ min-height: 0;
65
+ }
66
+
67
+ :host([loading]) [part='base'] {
68
+ /* loading state: host reflects attribute for consumer styling */
69
+ }
70
+ `,
71
+ ];
72
+ static define() {
73
+ if (!customElements.get(this.elementName)) {
74
+ customElements.define(this.elementName, this);
75
+ }
76
+ }
77
+ connectedCallback() {
78
+ super.connectedCallback();
79
+ this.rebuildModel();
80
+ }
81
+ disconnectedCallback() {
82
+ super.disconnectedCallback();
83
+ this.destroyObserver();
84
+ }
85
+ willUpdate(changedProperties) {
86
+ super.willUpdate(changedProperties);
87
+ if (changedProperties.has('label')) {
88
+ this.rebuildModel();
89
+ }
90
+ if (changedProperties.has('busy')) {
91
+ this.model.actions.setBusy(this.busy);
92
+ }
93
+ if (changedProperties.has('loading')) {
94
+ this.model.state.isLoading.set(this.loading);
95
+ }
96
+ if (changedProperties.has('error')) {
97
+ if (this.error) {
98
+ this.model.actions.setError('error');
99
+ }
100
+ else {
101
+ this.model.actions.clearError();
102
+ }
103
+ }
104
+ }
105
+ updated(changedProperties) {
106
+ super.updated(changedProperties);
107
+ this.setupObserver();
108
+ }
109
+ createModel(articles) {
110
+ return createFeed({
111
+ idBase: this.idBase,
112
+ articles,
113
+ ariaLabel: this.label || undefined,
114
+ });
115
+ }
116
+ getArticleElements() {
117
+ return Array.from(this.querySelectorAll('cv-feed-article'));
118
+ }
119
+ rebuildModel() {
120
+ const articleElements = this.getArticleElements();
121
+ const previousActiveId = this.model.state.activeArticleId();
122
+ const wasBusy = this.busy;
123
+ const wasLoading = this.loading;
124
+ const hadError = this.error;
125
+ const articles = articleElements.map((el) => ({
126
+ id: el.articleId,
127
+ disabled: el.disabled,
128
+ }));
129
+ this.model = createFeed({
130
+ idBase: this.idBase,
131
+ articles,
132
+ ariaLabel: this.label || undefined,
133
+ initialActiveArticleId: previousActiveId,
134
+ });
135
+ // Restore state
136
+ if (wasBusy)
137
+ this.model.actions.setBusy(true);
138
+ if (wasLoading)
139
+ this.model.state.isLoading.set(true);
140
+ if (hadError)
141
+ this.model.actions.setError('error');
142
+ this.syncArticleElements();
143
+ this.syncHostAttributes();
144
+ }
145
+ syncArticleElements() {
146
+ const articleElements = this.getArticleElements();
147
+ for (const el of articleElements) {
148
+ if (!el.articleId)
149
+ continue;
150
+ try {
151
+ const props = this.model.contracts.getArticleProps(el.articleId);
152
+ el.id = props.id;
153
+ el.setAttribute('role', props.role);
154
+ el.setAttribute('tabindex', props.tabindex);
155
+ el.setAttribute('aria-posinset', String(props['aria-posinset']));
156
+ el.setAttribute('aria-setsize', String(props['aria-setsize']));
157
+ el.setAttribute('data-active', props['data-active']);
158
+ if (props['aria-disabled']) {
159
+ el.setAttribute('aria-disabled', props['aria-disabled']);
160
+ }
161
+ else {
162
+ el.removeAttribute('aria-disabled');
163
+ }
164
+ el.active = props['data-active'] === 'true';
165
+ }
166
+ catch {
167
+ // Article may not be registered yet
168
+ }
169
+ }
170
+ }
171
+ syncHostAttributes() {
172
+ this.empty = this.model.state.isEmpty();
173
+ }
174
+ setupObserver() {
175
+ this.destroyObserver();
176
+ if (typeof IntersectionObserver === 'undefined')
177
+ return;
178
+ const topSentinel = this.shadowRoot?.querySelector('[part="sentinel-top"]');
179
+ const bottomSentinel = this.shadowRoot?.querySelector('[part="sentinel-bottom"]');
180
+ if (!topSentinel && !bottomSentinel)
181
+ return;
182
+ this.observer = new IntersectionObserver((entries) => {
183
+ for (const entry of entries) {
184
+ if (!entry.isIntersecting)
185
+ continue;
186
+ if (entry.target === bottomSentinel && this.model.state.canLoadMore()) {
187
+ this.model.actions.loadMore();
188
+ this.dispatchEvent(new CustomEvent('cv-load-more', {
189
+ detail: {},
190
+ bubbles: true,
191
+ composed: true,
192
+ }));
193
+ }
194
+ if (entry.target === topSentinel && this.model.state.canLoadNewer()) {
195
+ this.model.actions.loadNewer();
196
+ this.dispatchEvent(new CustomEvent('cv-load-newer', {
197
+ detail: {},
198
+ bubbles: true,
199
+ composed: true,
200
+ }));
201
+ }
202
+ }
203
+ }, { threshold: 0 });
204
+ if (topSentinel)
205
+ this.observer.observe(topSentinel);
206
+ if (bottomSentinel)
207
+ this.observer.observe(bottomSentinel);
208
+ }
209
+ destroyObserver() {
210
+ if (this.observer) {
211
+ this.observer.disconnect();
212
+ this.observer = null;
213
+ }
214
+ }
215
+ handleKeyDown(event) {
216
+ const result = this.model.actions.handleKeyDown({
217
+ key: event.key,
218
+ ctrlKey: event.ctrlKey,
219
+ metaKey: event.metaKey,
220
+ });
221
+ if (result === null)
222
+ return;
223
+ event.preventDefault();
224
+ if (result === 'next' || result === 'prev') {
225
+ this.syncArticleElements();
226
+ this.requestUpdate();
227
+ }
228
+ else if (result === 'exit-after') {
229
+ this.dispatchEvent(new CustomEvent('cv-exit-after', {
230
+ detail: {},
231
+ bubbles: true,
232
+ composed: true,
233
+ }));
234
+ }
235
+ else if (result === 'exit-before') {
236
+ this.dispatchEvent(new CustomEvent('cv-exit-before', {
237
+ detail: {},
238
+ bubbles: true,
239
+ composed: true,
240
+ }));
241
+ }
242
+ }
243
+ handleSlotChange() {
244
+ const articleElements = this.getArticleElements();
245
+ const articles = articleElements.map((el) => ({
246
+ id: el.articleId,
247
+ disabled: el.disabled,
248
+ }));
249
+ // Check if articles changed
250
+ const currentIds = this.model.state.articleIds();
251
+ const newIds = articles.map((a) => a.id);
252
+ const changed = currentIds.length !== newIds.length || currentIds.some((id, i) => id !== newIds[i]);
253
+ if (changed) {
254
+ const previousActiveId = this.model.state.activeArticleId();
255
+ const wasBusy = this.busy;
256
+ const wasLoading = this.loading;
257
+ const hadError = this.error;
258
+ this.model = createFeed({
259
+ idBase: this.idBase,
260
+ articles,
261
+ ariaLabel: this.label || undefined,
262
+ initialActiveArticleId: previousActiveId,
263
+ });
264
+ if (wasBusy)
265
+ this.model.actions.setBusy(true);
266
+ if (wasLoading)
267
+ this.model.state.isLoading.set(true);
268
+ if (hadError)
269
+ this.model.actions.setError('error');
270
+ this.syncArticleElements();
271
+ this.syncHostAttributes();
272
+ this.requestUpdate();
273
+ }
274
+ }
275
+ render() {
276
+ const feedProps = this.model.contracts.getFeedProps();
277
+ return html `
278
+ <div
279
+ id=${feedProps.id}
280
+ role=${feedProps.role}
281
+ aria-label=${feedProps['aria-label'] ?? nothing}
282
+ aria-labelledby=${feedProps['aria-labelledby'] ?? nothing}
283
+ aria-busy=${feedProps['aria-busy']}
284
+ part="base"
285
+ @keydown=${this.handleKeyDown}
286
+ >
287
+ <div part="sentinel-top"></div>
288
+ ${this.loading
289
+ ? html `
290
+ <div part="loading-indicator" aria-hidden="true">
291
+ <slot name="loading"></slot>
292
+ </div>
293
+ `
294
+ : nothing}
295
+ ${this.empty
296
+ ? html `
297
+ <slot name="empty" part="empty"></slot>
298
+ `
299
+ : nothing}
300
+ ${this.error
301
+ ? html `
302
+ <slot name="error" part="error"></slot>
303
+ `
304
+ : nothing}
305
+ <slot @slotchange=${this.handleSlotChange}></slot>
306
+ <div part="sentinel-bottom"></div>
307
+ </div>
308
+ `;
309
+ }
310
+ }
@@ -0,0 +1,30 @@
1
+ import { LitElement } from 'lit';
2
+ export declare class CVGridCell extends LitElement {
3
+ static elementName: string;
4
+ static get properties(): {
5
+ column: {
6
+ type: StringConstructor;
7
+ reflect: boolean;
8
+ };
9
+ disabled: {
10
+ type: BooleanConstructor;
11
+ reflect: boolean;
12
+ };
13
+ active: {
14
+ type: BooleanConstructor;
15
+ reflect: boolean;
16
+ };
17
+ selected: {
18
+ type: BooleanConstructor;
19
+ reflect: boolean;
20
+ };
21
+ };
22
+ column: string;
23
+ disabled: boolean;
24
+ active: boolean;
25
+ selected: boolean;
26
+ constructor();
27
+ static styles: import("lit").CSSResult[];
28
+ static define(): void;
29
+ protected render(): import("lit").TemplateResult<1>;
30
+ }
@@ -0,0 +1,57 @@
1
+ import { LitElement, css, html } from 'lit';
2
+ export class CVGridCell extends LitElement {
3
+ static elementName = 'cv-grid-cell';
4
+ static get properties() {
5
+ return {
6
+ column: { type: String, reflect: true },
7
+ disabled: { type: Boolean, reflect: true },
8
+ active: { type: Boolean, reflect: true },
9
+ selected: { type: Boolean, reflect: true },
10
+ };
11
+ }
12
+ constructor() {
13
+ super();
14
+ this.column = '';
15
+ this.disabled = false;
16
+ this.active = false;
17
+ this.selected = false;
18
+ }
19
+ static styles = [
20
+ css `
21
+ :host {
22
+ display: table-cell;
23
+ padding: var(--cv-space-2, 8px) var(--cv-space-3, 12px);
24
+ border-bottom: 1px solid color-mix(in oklab, var(--cv-color-border, #2a3245) 70%, transparent);
25
+ color: var(--cv-color-text, #e8ecf6);
26
+ outline: none;
27
+ }
28
+
29
+ :host([active]) {
30
+ background: color-mix(in oklab, var(--cv-color-primary, #65d7ff) 14%, transparent);
31
+ }
32
+
33
+ :host([selected]) {
34
+ background: color-mix(in oklab, var(--cv-color-primary, #65d7ff) 24%, transparent);
35
+ }
36
+
37
+ :host([disabled]) {
38
+ opacity: 0.55;
39
+ }
40
+
41
+ :host(:focus-visible) {
42
+ outline: 2px solid var(--cv-color-primary, #65d7ff);
43
+ outline-offset: -2px;
44
+ }
45
+ `,
46
+ ];
47
+ static define() {
48
+ if (!customElements.get(this.elementName)) {
49
+ customElements.define(this.elementName, this);
50
+ }
51
+ }
52
+ render() {
53
+ return html `
54
+ <slot></slot>
55
+ `;
56
+ }
57
+ }
@@ -0,0 +1,30 @@
1
+ import { LitElement } from 'lit';
2
+ export declare class CVGridColumn extends LitElement {
3
+ static elementName: string;
4
+ static get properties(): {
5
+ value: {
6
+ type: StringConstructor;
7
+ reflect: boolean;
8
+ };
9
+ label: {
10
+ type: StringConstructor;
11
+ reflect: boolean;
12
+ };
13
+ index: {
14
+ type: NumberConstructor;
15
+ reflect: boolean;
16
+ };
17
+ disabled: {
18
+ type: BooleanConstructor;
19
+ reflect: boolean;
20
+ };
21
+ };
22
+ value: string;
23
+ label: string;
24
+ index: number;
25
+ disabled: boolean;
26
+ constructor();
27
+ static styles: import("lit").CSSResult[];
28
+ static define(): void;
29
+ protected render(): import("lit").TemplateResult<1>;
30
+ }
@@ -0,0 +1,43 @@
1
+ import { LitElement, css, html } from 'lit';
2
+ export class CVGridColumn extends LitElement {
3
+ static elementName = 'cv-grid-column';
4
+ static get properties() {
5
+ return {
6
+ value: { type: String, reflect: true },
7
+ label: { type: String, reflect: true },
8
+ index: { type: Number, reflect: true },
9
+ disabled: { type: Boolean, reflect: true },
10
+ };
11
+ }
12
+ constructor() {
13
+ super();
14
+ this.value = '';
15
+ this.label = '';
16
+ this.index = 0;
17
+ this.disabled = false;
18
+ }
19
+ static styles = [
20
+ css `
21
+ :host {
22
+ display: table-cell;
23
+ padding: var(--cv-space-2, 8px) var(--cv-space-3, 12px);
24
+ border-bottom: 1px solid var(--cv-color-border, #2a3245);
25
+ color: var(--cv-color-text, #e8ecf6);
26
+ font-weight: 600;
27
+ background: color-mix(in oklab, var(--cv-color-surface, #141923) 82%, transparent);
28
+ }
29
+
30
+ :host([disabled]) {
31
+ opacity: 0.55;
32
+ }
33
+ `,
34
+ ];
35
+ static define() {
36
+ if (!customElements.get(this.elementName)) {
37
+ customElements.define(this.elementName, this);
38
+ }
39
+ }
40
+ render() {
41
+ return html `<slot>${this.label}</slot>`;
42
+ }
43
+ }
@@ -0,0 +1,30 @@
1
+ import { LitElement } from 'lit';
2
+ export type CVGridRowSlotchangeEvent = CustomEvent<null>;
3
+ export interface CVGridRowEventMap {
4
+ 'cv-grid-row-slotchange': CVGridRowSlotchangeEvent;
5
+ }
6
+ export declare class CVGridRow extends LitElement {
7
+ static elementName: string;
8
+ static get properties(): {
9
+ value: {
10
+ type: StringConstructor;
11
+ reflect: boolean;
12
+ };
13
+ index: {
14
+ type: NumberConstructor;
15
+ reflect: boolean;
16
+ };
17
+ disabled: {
18
+ type: BooleanConstructor;
19
+ reflect: boolean;
20
+ };
21
+ };
22
+ value: string;
23
+ index: number;
24
+ disabled: boolean;
25
+ constructor();
26
+ static styles: import("lit").CSSResult[];
27
+ static define(): void;
28
+ private handleSlotChange;
29
+ protected render(): import("lit").TemplateResult<1>;
30
+ }
@@ -0,0 +1,42 @@
1
+ import { LitElement, css, html } from 'lit';
2
+ export class CVGridRow extends LitElement {
3
+ static elementName = 'cv-grid-row';
4
+ static get properties() {
5
+ return {
6
+ value: { type: String, reflect: true },
7
+ index: { type: Number, reflect: true },
8
+ disabled: { type: Boolean, reflect: true },
9
+ };
10
+ }
11
+ constructor() {
12
+ super();
13
+ this.value = '';
14
+ this.index = 0;
15
+ this.disabled = false;
16
+ }
17
+ static styles = [
18
+ css `
19
+ :host {
20
+ display: table-row;
21
+ }
22
+
23
+ :host([disabled]) {
24
+ opacity: 0.55;
25
+ }
26
+ `,
27
+ ];
28
+ static define() {
29
+ if (!customElements.get(this.elementName)) {
30
+ customElements.define(this.elementName, this);
31
+ }
32
+ }
33
+ handleSlotChange() {
34
+ this.dispatchEvent(new CustomEvent('cv-grid-row-slotchange', {
35
+ bubbles: true,
36
+ composed: true,
37
+ }));
38
+ }
39
+ render() {
40
+ return html `<slot @slotchange=${this.handleSlotChange}></slot>`;
41
+ }
42
+ }