@ahriknow/lux 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.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +127 -0
  3. package/README_zh-CN.md +127 -0
  4. package/dist/components/lux-button/index.iife.min.js +292 -0
  5. package/dist/components/lux-button/index.min.js +292 -0
  6. package/dist/components/lux-code/index.iife.min.js +290 -0
  7. package/dist/components/lux-code/index.min.js +290 -0
  8. package/dist/components/lux-dropdown/index.iife.min.js +162 -0
  9. package/dist/components/lux-dropdown/index.min.js +162 -0
  10. package/dist/components/lux-example/index.iife.min.js +88 -0
  11. package/dist/components/lux-example/index.min.js +88 -0
  12. package/dist/components/lux-icon/index.iife.min.js +22 -0
  13. package/dist/components/lux-icon/index.min.js +22 -0
  14. package/dist/components/lux-input/index.iife.min.js +238 -0
  15. package/dist/components/lux-input/index.min.js +238 -0
  16. package/dist/components/lux-layout/index.iife.min.js +90 -0
  17. package/dist/components/lux-layout/index.min.js +90 -0
  18. package/dist/components/lux-menu/index.iife.min.js +193 -0
  19. package/dist/components/lux-menu/index.min.js +193 -0
  20. package/dist/components/lux-scroll/index.iife.min.js +137 -0
  21. package/dist/components/lux-scroll/index.min.js +137 -0
  22. package/dist/components/lux-switch/index.iife.min.js +116 -0
  23. package/dist/components/lux-switch/index.min.js +116 -0
  24. package/dist/components/lux-table/index.iife.min.js +67 -0
  25. package/dist/components/lux-table/index.min.js +67 -0
  26. package/dist/lux.core.min.js +1 -0
  27. package/dist/lux.i18n.min.js +1 -0
  28. package/dist/lux.iife.js +1822 -0
  29. package/dist/lux.iife.js.map +1 -0
  30. package/dist/lux.iife.min.js +1 -0
  31. package/dist/lux.js +1792 -0
  32. package/dist/lux.js.map +1 -0
  33. package/dist/lux.min.js +1 -0
  34. package/dist/lux.router.min.js +1 -0
  35. package/dist/lux.template.min.js +1 -0
  36. package/dist/lux.theme.min.js +1 -0
  37. package/dist/themes/dark.css +130 -0
  38. package/dist/themes/light.css +128 -0
  39. package/package.json +64 -0
  40. package/src/components/lux-button/index.js +319 -0
  41. package/src/components/lux-code/index.js +382 -0
  42. package/src/components/lux-dropdown/index.js +256 -0
  43. package/src/components/lux-example/index.js +117 -0
  44. package/src/components/lux-icon/index.js +180 -0
  45. package/src/components/lux-input/index.js +363 -0
  46. package/src/components/lux-layout/index.js +222 -0
  47. package/src/components/lux-menu/index.js +283 -0
  48. package/src/components/lux-scroll/index.js +349 -0
  49. package/src/components/lux-switch/index.js +203 -0
  50. package/src/components/lux-table/index.js +105 -0
  51. package/src/core.js +7 -0
  52. package/src/element.js +477 -0
  53. package/src/i18n/format.js +108 -0
  54. package/src/i18n/index.js +102 -0
  55. package/src/i18n/locale.js +26 -0
  56. package/src/index.js +22 -0
  57. package/src/router.js +330 -0
  58. package/src/template.js +402 -0
  59. package/src/theme/color.js +148 -0
  60. package/src/theme/create.js +97 -0
  61. package/src/theme/index.js +2 -0
  62. package/src/theme/tokens.js +128 -0
  63. package/src/themes/dark.css +130 -0
  64. package/src/themes/light.css +128 -0
@@ -0,0 +1,402 @@
1
+ /**
2
+ * Lux Template System
3
+ *
4
+ * Supports:
5
+ * - html/svg tagged templates with template caching
6
+ * - Child text interpolation: <div>${value}</div>
7
+ * - Event binding: <button @click=${handler}>
8
+ * - Property binding: <input .value=${val}>
9
+ * - Boolean attribute: <div ?hidden=${cond}>
10
+ * - Plain attribute: <div id=${val}>
11
+ * - Class binding: <div class=${classMap({...})}>
12
+ * - Style binding: <div style=${styleMap({...})}>
13
+ * - Ref binding: <input ref=${el => ...}>
14
+ * - Directives: repeat, when, classMap, styleMap, guard, show
15
+ * - Template caching, incremental DOM updates
16
+ * - nothing sentinel for clearing content
17
+ */
18
+
19
+ // ─── Template type markers ───
20
+ export const HTML_RESULT = 1;
21
+ export const SVG_RESULT = 2;
22
+
23
+ // ─── Sentinels ───
24
+ export const nothing = Symbol.for('lux-nothing');
25
+
26
+ // ─── Template cache ───
27
+ const templateCache = new WeakMap();
28
+
29
+ // ─── html / svg tagged template functions ───
30
+ export function html(strings, ...values) {
31
+ return { _$luxType$: HTML_RESULT, strings, values };
32
+ }
33
+
34
+ export function svg(strings, ...values) {
35
+ return { _$luxType$: SVG_RESULT, strings, values };
36
+ }
37
+
38
+ export function css(strings, ...values) {
39
+ return { _$luxType$: 3, strings, values };
40
+ }
41
+
42
+ export function isTemplateResult(value) {
43
+ return value && value._$luxType$ !== undefined;
44
+ }
45
+
46
+ // ─── HTML escaping ──
47
+ export function escapeHtml(value) {
48
+ if (value == null) return '';
49
+ const str = String(value);
50
+ if (str.indexOf('<') === -1 && str.indexOf('>') === -1 && str.indexOf('&') === -1) return str;
51
+ return str.replace(
52
+ /[<>&"']/g,
53
+ (c) => ({ '<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;', "'": '&#39;' })[c]
54
+ );
55
+ }
56
+
57
+ // ─── Part marker regex ──
58
+ const ATTR_BINDING_RE = /(?:([@.?][\w-]+)|(ref)|(class))=\s*$/;
59
+
60
+ // ─── Template parsing ──
61
+ function parseTemplate(strings) {
62
+ const parts = [];
63
+ let html = '';
64
+ for (let i = 0; i < strings.length; i++) {
65
+ html += strings[i];
66
+ if (i < strings.length - 1) {
67
+ const attrMatch = html.match(ATTR_BINDING_RE);
68
+ if (attrMatch) {
69
+ const prefixed = attrMatch[1];
70
+ const isRef = !!attrMatch[2];
71
+ const isClass = !!attrMatch[3];
72
+ let prefix = '';
73
+ let name = '';
74
+ if (prefixed) {
75
+ prefix = prefixed[0];
76
+ name = prefixed.slice(1);
77
+ } else if (isRef) {
78
+ prefix = 'ref';
79
+ name = 'ref';
80
+ } else if (isClass) {
81
+ prefix = 'class';
82
+ name = 'class';
83
+ }
84
+ const marker = `lux-attr-${i}`;
85
+ html = html.slice(0, -attrMatch[0].length) + `${marker}="${name}" `;
86
+ parts.push({ type: 'attr', name, prefix, marker, index: i });
87
+ } else {
88
+ const marker = `lux-${i}`;
89
+ html += `<!--${marker}-->`;
90
+ parts.push({ type: 'child', marker, index: i });
91
+ }
92
+ }
93
+ }
94
+ return { html, parts };
95
+ }
96
+
97
+ // ─── Commit functions ──
98
+
99
+ function commitValue(container, value, context) {
100
+ if (value === nothing || value == null) {
101
+ clearContainer(container);
102
+ return;
103
+ }
104
+
105
+ if (isRepeatResult(value)) {
106
+ commitRepeat(container, value, context);
107
+ return;
108
+ }
109
+
110
+ if (isTemplateResult(value)) {
111
+ render(value, container, context);
112
+ return;
113
+ }
114
+
115
+ if (Array.isArray(value)) {
116
+ clearContainer(container);
117
+ for (const item of value) {
118
+ if (isTemplateResult(item)) {
119
+ const span = document.createElement('span');
120
+ span.style.display = 'contents';
121
+ render(item, span, context);
122
+ container.appendChild(span);
123
+ } else if (item instanceof Node) {
124
+ container.appendChild(item);
125
+ } else if (item != null && item !== false) {
126
+ container.appendChild(document.createTextNode(String(item)));
127
+ }
128
+ }
129
+ return;
130
+ }
131
+
132
+ if (value instanceof Node) {
133
+ clearContainer(container);
134
+ container.appendChild(value);
135
+ return;
136
+ }
137
+
138
+ // Primitive — replace content (don't append)
139
+ if (container.childNodes.length === 1 && container.firstChild.nodeType === Node.TEXT_NODE) {
140
+ container.firstChild.textContent = String(value);
141
+ } else {
142
+ clearContainer(container);
143
+ container.appendChild(document.createTextNode(String(value)));
144
+ }
145
+ }
146
+
147
+ function clearContainer(container) {
148
+ while (container.firstChild) {
149
+ container.removeChild(container.firstChild);
150
+ }
151
+ }
152
+
153
+ function commitAttrPart(part, value) {
154
+ const { element, name, prefix } = part;
155
+
156
+ switch (prefix) {
157
+ case '@': {
158
+ // Event binding
159
+ const oldHandler = part.committedValue;
160
+
161
+ // Determine if we should remove/add based on value changes
162
+ const isNothing = value == null || value === nothing;
163
+ const shouldRemoveListener =
164
+ (isNothing && oldHandler != null) ||
165
+ value?.capture !== oldHandler?.capture ||
166
+ value?.once !== oldHandler?.once ||
167
+ value?.passive !== oldHandler?.passive;
168
+
169
+ const shouldAddListener = !isNothing && (oldHandler == null || shouldRemoveListener);
170
+
171
+ if (shouldRemoveListener) {
172
+ element.removeEventListener(name, part._handler || oldHandler, oldHandler);
173
+ }
174
+
175
+ if (shouldAddListener) {
176
+ if (typeof value === 'function') {
177
+ // Wrap handler to preserve `this` as the host element
178
+ const host =
179
+ part._host ||
180
+ (part._host = {
181
+ handleEvent(e) {
182
+ const fn = part.committedValue;
183
+ if (typeof fn === 'function') {
184
+ // Use host element (custom element instance) as `this`
185
+ const hostEl = element.getRootNode().host || element;
186
+ fn.call(hostEl, e);
187
+ }
188
+ },
189
+ });
190
+ part._handler = host;
191
+ element.addEventListener(name, host);
192
+ } else if (typeof value === 'object' && value?.handleEvent) {
193
+ // EventListenerObject: { handleEvent(event) }
194
+ const host = { handleEvent: (e) => value.handleEvent.call(value, e) };
195
+ part._handler = host;
196
+ element.addEventListener(name, host, {
197
+ capture: value.capture,
198
+ once: value.once,
199
+ passive: value.passive,
200
+ });
201
+ }
202
+ }
203
+
204
+ part.committedValue = value;
205
+ break;
206
+ }
207
+ case '.': {
208
+ // Property binding
209
+ element[name] = value === nothing ? undefined : value;
210
+ break;
211
+ }
212
+ case '?': {
213
+ // Boolean attribute binding
214
+ element.toggleAttribute(name, !!value);
215
+ break;
216
+ }
217
+ case 'ref': {
218
+ // Ref binding
219
+ if (typeof value === 'function') {
220
+ value(element);
221
+ }
222
+ break;
223
+ }
224
+ case 'class': {
225
+ // Class binding
226
+ if (typeof value === 'string') {
227
+ element.className = value;
228
+ } else if (typeof value === 'object' && value != null) {
229
+ const existing = element.className || '';
230
+ const names = existing ? existing.split(/\s+/) : [];
231
+ for (const [cls, active] of Object.entries(value)) {
232
+ if (active) {
233
+ if (!names.includes(cls)) names.push(cls);
234
+ } else {
235
+ const idx = names.indexOf(cls);
236
+ if (idx !== -1) names.splice(idx, 1);
237
+ }
238
+ }
239
+ element.className = names.filter(Boolean).join(' ');
240
+ }
241
+ break;
242
+ }
243
+ default: {
244
+ // Plain attribute
245
+ if (value == null || value === false) {
246
+ element.removeAttribute(name);
247
+ } else {
248
+ element.setAttribute(name, value === true ? '' : String(value));
249
+ }
250
+ }
251
+ }
252
+ }
253
+
254
+ // ─── render() function ──
255
+
256
+ export function render(result, container, context) {
257
+ if (!isTemplateResult(result)) {
258
+ container.textContent = result ?? '';
259
+ return;
260
+ }
261
+
262
+ const { strings, values } = result;
263
+
264
+ // Incremental update
265
+ if (container._luxActiveParts && container._luxStrings === strings) {
266
+ for (const part of container._luxActiveParts) {
267
+ if (part.index < values.length) {
268
+ if (part.type === 'child') {
269
+ commitValue(part.span, values[part.index], context);
270
+ } else {
271
+ commitAttrPart(part, values[part.index]);
272
+ }
273
+ }
274
+ }
275
+ return;
276
+ }
277
+
278
+ // First render — build part list
279
+ const tpl = document.createElement('template');
280
+ const parsed = parseTemplate(strings);
281
+ tpl.innerHTML = parsed.html;
282
+ const fragment = tpl.content.cloneNode(true);
283
+ const activeParts = [];
284
+
285
+ for (const part of parsed.parts) {
286
+ if (part.type === 'child') {
287
+ const walker = document.createTreeWalker(fragment, NodeFilter.SHOW_COMMENT);
288
+ let node;
289
+ while ((node = walker.nextNode())) {
290
+ if (node.data === part.marker) {
291
+ const span = document.createElement('span');
292
+ span.style.display = 'contents';
293
+ node.parentNode.replaceChild(span, node);
294
+ commitValue(span, values[part.index], context);
295
+ activeParts.push({ type: 'child', span, index: part.index });
296
+ break;
297
+ }
298
+ }
299
+ } else {
300
+ const element = fragment.querySelector(`[${part.marker}]`);
301
+ if (element) {
302
+ element.removeAttribute(part.marker);
303
+ const ap = {
304
+ type: 'attr',
305
+ element,
306
+ name: part.name,
307
+ prefix: part.prefix,
308
+ index: part.index,
309
+ committedValue: undefined,
310
+ };
311
+ commitAttrPart(ap, values[part.index]);
312
+ activeParts.push(ap);
313
+ }
314
+ }
315
+ }
316
+
317
+ container.textContent = '';
318
+ container.appendChild(fragment);
319
+ container._luxActiveParts = activeParts;
320
+ container._luxStrings = strings;
321
+ }
322
+
323
+ // ─── Directives ──
324
+
325
+ /**
326
+ * repeat(items, keyFn, renderFn) — keyed list rendering
327
+ */
328
+ export function repeat(items, keyFn, renderFn) {
329
+ return { _type: 'repeat', items, keyFn, renderFn };
330
+ }
331
+
332
+ function isRepeatResult(value) {
333
+ return value && value._type === 'repeat';
334
+ }
335
+
336
+ function commitRepeat(container, value, context) {
337
+ const { items, keyFn, renderFn } = value;
338
+ const state = container._repeatState;
339
+
340
+ // Clear old content
341
+ if (state) {
342
+ for (const entry of state.entries) {
343
+ if (entry.span && entry.span.parentNode) {
344
+ entry.span.parentNode.removeChild(entry.span);
345
+ }
346
+ }
347
+ }
348
+
349
+ // Build new content
350
+ const frag = document.createDocumentFragment();
351
+ const entries = [];
352
+ for (const item of items) {
353
+ const key = keyFn(item);
354
+ const result = renderFn(item);
355
+ const span = document.createElement('span');
356
+ span.style.display = 'contents';
357
+ if (isTemplateResult(result)) {
358
+ render(result, span, context);
359
+ } else if (result != null && result !== false) {
360
+ span.appendChild(document.createTextNode(String(result)));
361
+ }
362
+ frag.appendChild(span);
363
+ entries.push({ key, result, span });
364
+ }
365
+ container.appendChild(frag);
366
+ container._repeatState = { entries };
367
+ }
368
+
369
+ /**
370
+ * when(condition, trueFn, falseFn) — conditional rendering
371
+ */
372
+ export function when(condition, trueFn, falseFn = () => '') {
373
+ return condition ? trueFn() : falseFn();
374
+ }
375
+
376
+ /**
377
+ * show(condition, content) — show/hide element
378
+ */
379
+ export function show(condition, content = '') {
380
+ return condition ? content : '';
381
+ }
382
+
383
+ /**
384
+ * classMap(classes) — dynamic class binding helper
385
+ */
386
+ export function classMap(classes) {
387
+ return classes;
388
+ }
389
+
390
+ /**
391
+ * styleMap(styles) — dynamic style binding helper
392
+ */
393
+ export function styleMap(styles) {
394
+ return styles;
395
+ }
396
+
397
+ /**
398
+ * guard(dependencies, fn) — re-render only when dependencies change
399
+ */
400
+ export function guard(dependencies, fn) {
401
+ return fn();
402
+ }
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Color utilities — HSL-based color generation from a seed color
3
+ */
4
+
5
+ // ─── Conversion ───
6
+
7
+ export function hexToRgb(hex) {
8
+ hex = hex.replace('#', '');
9
+ if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
10
+ return {
11
+ r: parseInt(hex.slice(0, 2), 16),
12
+ g: parseInt(hex.slice(2, 4), 16),
13
+ b: parseInt(hex.slice(4, 6), 16),
14
+ };
15
+ }
16
+
17
+ export function rgbToHsl(r, g, b) {
18
+ r /= 255;
19
+ g /= 255;
20
+ b /= 255;
21
+ const max = Math.max(r, g, b),
22
+ min = Math.min(r, g, b);
23
+ let h,
24
+ s,
25
+ l = (max + min) / 2;
26
+
27
+ if (max === min) {
28
+ h = s = 0;
29
+ } else {
30
+ const d = max - min;
31
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
32
+ switch (max) {
33
+ case r:
34
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
35
+ break;
36
+ case g:
37
+ h = ((b - r) / d + 2) / 6;
38
+ break;
39
+ case b:
40
+ h = ((r - g) / d + 4) / 6;
41
+ break;
42
+ }
43
+ }
44
+ return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) };
45
+ }
46
+
47
+ export function hslToRgb(h, s, l) {
48
+ h /= 360;
49
+ s /= 100;
50
+ l /= 100;
51
+ let r, g, b;
52
+
53
+ if (s === 0) {
54
+ r = g = b = l;
55
+ } else {
56
+ const hue2rgb = (p, q, t) => {
57
+ if (t < 0) t += 1;
58
+ if (t > 1) t -= 1;
59
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
60
+ if (t < 1 / 2) return q;
61
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
62
+ return p;
63
+ };
64
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
65
+ const p = 2 * l - q;
66
+ r = hue2rgb(p, q, h + 1 / 3);
67
+ g = hue2rgb(p, q, h);
68
+ b = hue2rgb(p, q, h - 1 / 3);
69
+ }
70
+
71
+ return {
72
+ r: Math.round(r * 255),
73
+ g: Math.round(g * 255),
74
+ b: Math.round(b * 255),
75
+ };
76
+ }
77
+
78
+ export function hexToHsl(hex) {
79
+ const { r, g, b } = hexToRgb(hex);
80
+ return rgbToHsl(r, g, b);
81
+ }
82
+
83
+ export function hslToHex(h, s, l) {
84
+ const { r, g, b } = hslToRgb(h, s, l);
85
+ return '#' + [r, g, b].map((x) => x.toString(16).padStart(2, '0')).join('');
86
+ }
87
+
88
+ export function rgbString(r, g, b) {
89
+ return `${r} ${g} ${b}`;
90
+ }
91
+
92
+ // ─── Palette generation ───
93
+
94
+ /**
95
+ * Generate a 10-step palette (50-900) from a seed HSL.
96
+ * Lightness curve: 50→97%, 100→93%, 200→86%, 300→76%, 400→64%,
97
+ * 500→seed%, 600→45%, 700→38%, 800→28%, 900→18%
98
+ */
99
+ export function generatePalette(h, s, l) {
100
+ const steps = [
101
+ [50, 97, 90],
102
+ [100, 93, 85],
103
+ [200, 86, 78],
104
+ [300, 76, 68],
105
+ [400, 64, 58],
106
+ [500, s, l], // seed
107
+ [600, s, 45],
108
+ [700, s, 38],
109
+ [800, s, 28],
110
+ [900, s, 18],
111
+ ];
112
+
113
+ const palette = {};
114
+ for (const [step, sat, light] of steps) {
115
+ palette[step] = hslToHex(h, sat, light);
116
+ }
117
+ return palette;
118
+ }
119
+
120
+ /**
121
+ * Generate semantic colors by shifting hue from seed.
122
+ * success: +120°, warning: +40°, error: -20° (or +340°), info: +200°
123
+ */
124
+ export function generateSemantic(h, s, l) {
125
+ const shift = (hue, sat, light) => {
126
+ const h2 = ((hue % 360) + 360) % 360;
127
+ return hslToHex(h2, sat, light);
128
+ };
129
+
130
+ return {
131
+ success: {
132
+ 500: shift(h + 120, 72, 45),
133
+ light: shift(h + 120, 60, 92),
134
+ },
135
+ warning: {
136
+ 500: shift(h + 40, 85, 55),
137
+ light: shift(h + 40, 80, 93),
138
+ },
139
+ error: {
140
+ 500: shift(h - 20, 78, 55),
141
+ light: shift(h - 20, 70, 93),
142
+ },
143
+ info: {
144
+ 500: shift(h + 200, 72, 55),
145
+ light: shift(h + 200, 65, 93),
146
+ },
147
+ };
148
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * createTheme — generate a complete theme from colors.
3
+ *
4
+ * Usage:
5
+ * const theme = createTheme({ primary: '#6c5ce7' });
6
+ * const theme = createTheme({
7
+ * primary: '#6c5ce7', success: '#10b981',
8
+ * warning: '#f59e0b', error: '#ef4444', info: '#3b82f6'
9
+ * });
10
+ * theme.setColors({ success: '#22c55e' });
11
+ * theme.apply();
12
+ */
13
+
14
+ import { hexToHsl, hslToHex } from './color.js';
15
+ import { generatePalette } from './color.js';
16
+ import { generateLightTokens, generateDarkTokens, tokensToCSS } from './tokens.js';
17
+
18
+ const defaultColors = {
19
+ primary: '#6c5ce7',
20
+ success: '#10b981',
21
+ warning: '#f59e0b',
22
+ error: '#ef4444',
23
+ info: '#3b82f6',
24
+ };
25
+
26
+ export function createTheme(options = {}) {
27
+ if (typeof options === 'string') options = { primary: options };
28
+
29
+ const _colors = { ...defaultColors, ...options.colors };
30
+ let _dark = options.dark ?? false;
31
+ let _radius = options.radius ?? '8px';
32
+ let _font =
33
+ options.font ?? '-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif';
34
+
35
+ function _build() {
36
+ const { h, s, l } = hexToHsl(_colors.primary);
37
+ const palette = generatePalette(h, s, l);
38
+
39
+ const semantic = {};
40
+ for (const [name, hex] of Object.entries(_colors)) {
41
+ if (name === 'primary') continue;
42
+ const { h: sh, s: ss } = hexToHsl(hex);
43
+ semantic[name] = { 500: hex, light: hslToHex(sh, 60, 93) };
44
+ }
45
+
46
+ const tokens = _dark
47
+ ? generateDarkTokens(palette, semantic)
48
+ : generateLightTokens(palette, semantic);
49
+
50
+ tokens['lux-radius'] = _radius;
51
+ tokens['lux-font'] = _font;
52
+
53
+ return tokens;
54
+ }
55
+
56
+ function _inject(tokens) {
57
+ let el = document.getElementById('lux-theme');
58
+ if (!el) {
59
+ el = document.createElement('style');
60
+ el.id = 'lux-theme';
61
+ document.head.appendChild(el);
62
+ }
63
+ el.textContent = tokensToCSS(tokens);
64
+ }
65
+
66
+ return {
67
+ apply() {
68
+ _inject(_build());
69
+ },
70
+
71
+ setColors(patch) {
72
+ Object.assign(_colors, patch);
73
+ this.apply();
74
+ },
75
+
76
+ setDark(dark) {
77
+ _dark = dark;
78
+ this.apply();
79
+ },
80
+ getCSS() {
81
+ return tokensToCSS(_build());
82
+ },
83
+ getTokens() {
84
+ return _build();
85
+ },
86
+ getColors() {
87
+ return { ..._colors };
88
+ },
89
+
90
+ get primary() {
91
+ return _colors.primary;
92
+ },
93
+ get dark() {
94
+ return _dark;
95
+ },
96
+ };
97
+ }
@@ -0,0 +1,2 @@
1
+ export { createTheme } from './create.js';
2
+ export { hexToHsl, hslToHex, hexToRgb, rgbToHsl } from './color.js';