@santi020k/lumen-core 3.0.1 → 4.0.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.
- package/PHONE_FLAG_LICENSE.txt +21 -0
- package/README.md +363 -3
- package/THIRD_PARTY_NOTICES.md +16 -2
- package/dist/ai-surfaces.d.ts +25 -0
- package/dist/ai-surfaces.d.ts.map +1 -0
- package/dist/ai-surfaces.js +162 -0
- package/dist/amount-field.d.ts +22 -0
- package/dist/amount-field.d.ts.map +1 -0
- package/dist/amount-field.js +207 -0
- package/dist/attachments.d.ts +15 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +123 -0
- package/dist/bullet-chart.d.ts +33 -0
- package/dist/bullet-chart.d.ts.map +1 -0
- package/dist/bullet-chart.js +80 -0
- package/dist/chart-activation.d.ts +32 -0
- package/dist/chart-activation.d.ts.map +1 -0
- package/dist/chart-activation.js +97 -0
- package/dist/chart-interaction.d.ts +12 -0
- package/dist/chart-interaction.d.ts.map +1 -0
- package/dist/chart-interaction.js +274 -0
- package/dist/chart-models.d.ts +156 -0
- package/dist/chart-models.d.ts.map +1 -0
- package/dist/chart-models.js +348 -0
- package/dist/chart-motion.d.ts +6 -0
- package/dist/chart-motion.d.ts.map +1 -0
- package/dist/chart-motion.js +107 -0
- package/dist/charts.d.ts +58 -3
- package/dist/charts.d.ts.map +1 -1
- package/dist/charts.js +247 -18
- package/dist/code.js +1 -1
- package/dist/combobox.d.ts +7 -0
- package/dist/combobox.d.ts.map +1 -0
- package/dist/combobox.js +253 -0
- package/dist/comparison-chart.d.ts +32 -0
- package/dist/comparison-chart.d.ts.map +1 -0
- package/dist/comparison-chart.js +64 -0
- package/dist/components.d.ts +210 -25
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +102 -26
- package/dist/dashboard.d.ts +16 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/dashboard.js +21 -0
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +21 -5
- package/dist/dates.d.ts +13 -0
- package/dist/dates.d.ts.map +1 -0
- package/dist/dates.js +37 -0
- package/dist/device-frame.d.ts +25 -0
- package/dist/device-frame.d.ts.map +1 -0
- package/dist/device-frame.js +50 -0
- package/dist/direction.d.ts +3 -0
- package/dist/direction.d.ts.map +1 -0
- package/dist/direction.js +10 -0
- package/dist/extended-charts.d.ts +95 -0
- package/dist/extended-charts.d.ts.map +1 -0
- package/dist/extended-charts.js +175 -0
- package/dist/figma.d.ts.map +1 -1
- package/dist/figma.js +10 -1
- package/dist/forms.d.ts.map +1 -1
- package/dist/forms.js +18 -4
- package/dist/icon-data.generated.d.ts +1 -1
- package/dist/icon-data.generated.d.ts.map +1 -1
- package/dist/icon-data.generated.js +1 -1
- package/dist/icons.js +3 -4
- package/dist/illustrations.generated.d.ts +1 -1
- package/dist/image-comparison.d.ts +14 -0
- package/dist/image-comparison.d.ts.map +1 -0
- package/dist/image-comparison.js +48 -0
- package/dist/index.d.ts +35 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -3
- package/dist/media-viewport.d.ts +24 -0
- package/dist/media-viewport.d.ts.map +1 -0
- package/dist/media-viewport.js +119 -0
- package/dist/media-workspace.d.ts +27 -0
- package/dist/media-workspace.d.ts.map +1 -0
- package/dist/media-workspace.js +83 -0
- package/dist/message-scroller.d.ts +14 -0
- package/dist/message-scroller.d.ts.map +1 -0
- package/dist/message-scroller.js +113 -0
- package/dist/motion-workflows.d.ts +24 -0
- package/dist/motion-workflows.d.ts.map +1 -0
- package/dist/motion-workflows.js +220 -0
- package/dist/motion.d.ts +12 -0
- package/dist/motion.d.ts.map +1 -0
- package/dist/motion.js +96 -0
- package/dist/native-input.d.ts +25 -0
- package/dist/native-input.d.ts.map +1 -0
- package/dist/native-input.js +188 -0
- package/dist/phone-flags.generated.d.ts +2 -0
- package/dist/phone-flags.generated.d.ts.map +1 -0
- package/dist/phone-flags.generated.js +263 -0
- package/dist/phone.d.ts +4 -0
- package/dist/phone.d.ts.map +1 -1
- package/dist/phone.js +6 -1
- package/dist/rich-text.d.ts +7 -0
- package/dist/rich-text.d.ts.map +1 -1
- package/dist/rich-text.js +13 -0
- package/dist/rive.d.ts +37 -0
- package/dist/rive.d.ts.map +1 -0
- package/dist/rive.js +129 -0
- package/dist/schedule.d.ts.map +1 -1
- package/dist/schedule.js +63 -23
- package/dist/tab-indicator.d.ts +3 -0
- package/dist/tab-indicator.d.ts.map +1 -0
- package/dist/tab-indicator.js +57 -0
- package/dist/theme-audit.d.ts +16 -0
- package/dist/theme-audit.d.ts.map +1 -0
- package/dist/theme-audit.js +57 -0
- package/dist/theme-builder.d.ts +7 -1
- package/dist/theme-builder.d.ts.map +1 -1
- package/dist/theme-builder.js +45 -23
- package/dist/theme-presets.generated.d.ts +217 -0
- package/dist/theme-presets.generated.d.ts.map +1 -0
- package/dist/theme-presets.generated.js +231 -0
- package/dist/theme.d.ts +11 -3
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +56 -6
- package/dist/virtual-collection.d.ts +14 -0
- package/dist/virtual-collection.d.ts.map +1 -0
- package/dist/virtual-collection.js +132 -0
- package/dist/virtual-list.d.ts +7 -0
- package/dist/virtual-list.d.ts.map +1 -0
- package/dist/virtual-list.js +135 -0
- package/dist/virtual-window.d.ts +19 -0
- package/dist/virtual-window.d.ts.map +1 -0
- package/dist/virtual-window.js +84 -0
- package/dist/visual-effects.d.ts +6 -0
- package/dist/visual-effects.d.ts.map +1 -0
- package/dist/visual-effects.js +44 -0
- package/dist/world-map-data.generated.d.ts +9 -0
- package/dist/world-map-data.generated.d.ts.map +1 -0
- package/dist/world-map-data.generated.js +240 -0
- package/dist/world-map-navigation.d.ts +16 -0
- package/dist/world-map-navigation.d.ts.map +1 -0
- package/dist/world-map-navigation.js +53 -0
- package/dist/world-map-pan.d.ts +3 -0
- package/dist/world-map-pan.d.ts.map +1 -0
- package/dist/world-map-pan.js +66 -0
- package/dist/world-map-zoom.d.ts +13 -0
- package/dist/world-map-zoom.d.ts.map +1 -0
- package/dist/world-map-zoom.js +61 -0
- package/dist/world-map.d.ts +71 -0
- package/dist/world-map.d.ts.map +1 -0
- package/dist/world-map.js +143 -0
- package/package.json +51 -4
package/dist/phone.d.ts
CHANGED
|
@@ -21,4 +21,8 @@ export declare const getLumenPhoneCountries: (options?: LumenPhoneCountryOptions
|
|
|
21
21
|
export declare const createEmptyLumenPhoneNumber: (country: LumenPhoneCountry) => LumenPhoneNumber;
|
|
22
22
|
export declare const sanitizeLumenPhoneInput: (input: string) => string;
|
|
23
23
|
export declare const resolveLumenPhoneNumber: (country: LumenPhoneCountry, input: string, options?: LumenPhoneCountryOptions) => LumenPhoneNumber;
|
|
24
|
+
/** Bundled, offline flag artwork shared by the web and React Native adapters. */
|
|
25
|
+
export declare const getLumenPhoneFlagSource: (regionCode: string) => string | null;
|
|
26
|
+
/** A complete number for read-only presentation; incomplete input stays editable. */
|
|
27
|
+
export declare const formatLumenPhoneNumber: (value: LumenPhoneNumber) => string;
|
|
24
28
|
//# sourceMappingURL=phone.d.ts.map
|
package/dist/phone.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"phone.d.ts","sourceRoot":"","sources":["../src/phone.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAGI,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"phone.d.ts","sourceRoot":"","sources":["../src/phone.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAGI,MAAM,uBAAuB,CAAA;AAMnD,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,IAAI,MAAM,EAAE,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,WAAW,CAAA;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,iBAAiB,CAAA;IAC1B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;CACpC;AAcD,eAAO,MAAM,iBAAiB,GAAI,YAAY,MAAM,KAAG,MAStD,CAAA;AAED,eAAO,MAAM,oBAAoB,GAC/B,YAAY,MAAM,EAClB,UAAS,wBAA6B,KACrC,iBAAiB,GAAG,IAiBtB,CAAA;AAED,eAAO,MAAM,sBAAsB,GACjC,UAAS,wBAA6B,KACrC,SAAS,iBAAiB,EAG8D,CAAA;AAE3F,eAAO,MAAM,2BAA2B,GACtC,SAAS,iBAAiB,KACzB,gBAKD,CAAA;AAEF,eAAO,MAAM,uBAAuB,GAAI,OAAO,MAAM,KAAG,MAYvD,CAAA;AAgCD,eAAO,MAAM,uBAAuB,GAClC,SAAS,iBAAiB,EAC1B,OAAO,MAAM,EACb,UAAS,wBAA6B,KACrC,gBA6BF,CAAA;AAED,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,GAAI,YAAY,MAAM,KAAG,MAAM,GAAG,IAErE,CAAA;AAED,qFAAqF;AACrF,eAAO,MAAM,sBAAsB,GAAI,OAAO,gBAAgB,KAAG,MAEhE,CAAA"}
|
package/dist/phone.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AsYouType, getCountries, getCountryCallingCode, isSupportedCountry } from 'libphonenumber-js/max';
|
|
2
|
+
import { lumenPhoneFlagSources } from './phone-flags.generated.js';
|
|
2
3
|
const regionalIndicatorA = 0x1F1E6;
|
|
3
4
|
const getRegionDisplayNames = (locale) => {
|
|
4
5
|
if (typeof Intl.DisplayNames !== 'function')
|
|
@@ -12,7 +13,7 @@ const getRegionDisplayNames = (locale) => {
|
|
|
12
13
|
};
|
|
13
14
|
export const getLumenPhoneFlag = (regionCode) => {
|
|
14
15
|
const normalizedRegion = regionCode.toUpperCase();
|
|
15
|
-
if (normalizedRegion
|
|
16
|
+
if (!/^[A-Z]{2}$/.test(normalizedRegion))
|
|
16
17
|
return '';
|
|
17
18
|
const first = String.fromCodePoint(regionalIndicatorA + normalizedRegion.charCodeAt(0) - 65);
|
|
18
19
|
const second = String.fromCodePoint(regionalIndicatorA + normalizedRegion.charCodeAt(1) - 65);
|
|
@@ -88,3 +89,7 @@ export const resolveLumenPhoneNumber = (country, input, options = {}) => {
|
|
|
88
89
|
nationalNumber: resolveLumenNationalPhoneNumber(formattedInput, formattedNationalNumber, normalized)
|
|
89
90
|
};
|
|
90
91
|
};
|
|
92
|
+
/** Bundled, offline flag artwork shared by the web and React Native adapters. */
|
|
93
|
+
export const getLumenPhoneFlagSource = (regionCode) => (lumenPhoneFlagSources[regionCode.toUpperCase()] ?? null);
|
|
94
|
+
/** A complete number for read-only presentation; incomplete input stays editable. */
|
|
95
|
+
export const formatLumenPhoneNumber = (value) => (value.isValid && value.e164 ? value.e164 : value.nationalNumber);
|
package/dist/rich-text.d.ts
CHANGED
|
@@ -5,6 +5,13 @@ export interface LumenRichTextCommandDetail {
|
|
|
5
5
|
executed: boolean;
|
|
6
6
|
value?: string;
|
|
7
7
|
}
|
|
8
|
+
export interface LumenRichTextCommandRequest {
|
|
9
|
+
command: string;
|
|
10
|
+
value?: string;
|
|
11
|
+
}
|
|
12
|
+
export type LumenRichTextCommandRequestEvent = CustomEvent<LumenRichTextCommandDetail>;
|
|
13
|
+
/** A canceled request belongs to the external engine, including unsuccessful commands. */
|
|
14
|
+
export declare const executeLumenRichTextCommand: (root: HTMLElement | null, request: LumenRichTextCommandRequest, fallback: () => boolean, commandHandler?: (request: LumenRichTextCommandRequest) => boolean) => boolean;
|
|
8
15
|
export interface LumenRichTextChangeDetail {
|
|
9
16
|
html: string;
|
|
10
17
|
text: string;
|
package/dist/rich-text.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rich-text.d.ts","sourceRoot":"","sources":["../src/rich-text.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,2BAA2B,mIAS7B,CAAA;AAEX,MAAM,MAAM,0BAA0B,GAAG,OAAO,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAEnF,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAwBD,eAAO,MAAM,4BAA4B,GACvC,SAAS,MAAM,KACd,OAAO,IAAI,0BAAyD,CAAA;AAEvE,eAAO,MAAM,wBAAwB,GACnC,OAAO,0BAA0B,KAChC,MAAM,GAAG,SAQX,CAAA"}
|
|
1
|
+
{"version":3,"file":"rich-text.d.ts","sourceRoot":"","sources":["../src/rich-text.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,2BAA2B,mIAS7B,CAAA;AAEX,MAAM,MAAM,0BAA0B,GAAG,OAAO,2BAA2B,CAAC,MAAM,CAAC,CAAA;AAEnF,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,gCAAgC,GAAG,WAAW,CAAC,0BAA0B,CAAC,CAAA;AAEtF,0FAA0F;AAC1F,eAAO,MAAM,2BAA2B,GACtC,MAAM,WAAW,GAAG,IAAI,EACxB,SAAS,2BAA2B,EACpC,UAAU,MAAM,OAAO,EACvB,iBAAiB,CAAC,OAAO,EAAE,2BAA2B,KAAK,OAAO,KACjE,OAgBF,CAAA;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAwBD,eAAO,MAAM,4BAA4B,GACvC,SAAS,MAAM,KACd,OAAO,IAAI,0BAAyD,CAAA;AAEvE,eAAO,MAAM,wBAAwB,GACnC,OAAO,0BAA0B,KAChC,MAAM,GAAG,SAQX,CAAA"}
|
package/dist/rich-text.js
CHANGED
|
@@ -8,6 +8,19 @@ export const lumenRichTextToggleCommands = Object.freeze([
|
|
|
8
8
|
'insertOrderedList',
|
|
9
9
|
'insertUnorderedList'
|
|
10
10
|
]);
|
|
11
|
+
/** A canceled request belongs to the external engine, including unsuccessful commands. */
|
|
12
|
+
export const executeLumenRichTextCommand = (root, request, fallback, commandHandler) => {
|
|
13
|
+
const detail = { ...request, executed: false };
|
|
14
|
+
const event = typeof CustomEvent === 'undefined' ?
|
|
15
|
+
undefined :
|
|
16
|
+
new CustomEvent('ui:editor-command-request', { bubbles: true, cancelable: true, detail });
|
|
17
|
+
if (event && root) {
|
|
18
|
+
root.dispatchEvent(event);
|
|
19
|
+
if (event.defaultPrevented)
|
|
20
|
+
return detail.executed;
|
|
21
|
+
}
|
|
22
|
+
return commandHandler ? commandHandler(request) : fallback();
|
|
23
|
+
};
|
|
11
24
|
const toggleCommands = new Set(lumenRichTextToggleCommands);
|
|
12
25
|
const shortcuts = {
|
|
13
26
|
b: 'bold',
|
package/dist/rive.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Rive, type RiveParameters } from '@rive-app/canvas';
|
|
2
|
+
export type LumenRiveStatus = 'loading' | 'ready' | 'error' | 'destroyed';
|
|
3
|
+
export interface LumenRiveBinding {
|
|
4
|
+
boolean: (path: string) => {
|
|
5
|
+
value: boolean;
|
|
6
|
+
} | null;
|
|
7
|
+
number: (path: string) => {
|
|
8
|
+
value: number;
|
|
9
|
+
} | null;
|
|
10
|
+
string: (path: string) => {
|
|
11
|
+
value: string;
|
|
12
|
+
} | null;
|
|
13
|
+
trigger: (path: string) => {
|
|
14
|
+
trigger: () => void;
|
|
15
|
+
} | null;
|
|
16
|
+
}
|
|
17
|
+
export type LumenRiveRuntime = Pick<Rive, 'cleanup' | 'pause' | 'play' | 'resizeDrawingSurfaceToCanvas'> & {
|
|
18
|
+
readonly viewModelInstance: LumenRiveBinding | null;
|
|
19
|
+
};
|
|
20
|
+
export interface LumenRiveOptions {
|
|
21
|
+
autoplay?: boolean;
|
|
22
|
+
canvas: HTMLCanvasElement;
|
|
23
|
+
createRuntime?: (parameters: RiveParameters) => LumenRiveRuntime;
|
|
24
|
+
onStatus?: (status: LumenRiveStatus) => void;
|
|
25
|
+
src: string;
|
|
26
|
+
stateMachine: string;
|
|
27
|
+
}
|
|
28
|
+
export interface LumenRiveController {
|
|
29
|
+
destroy: () => void;
|
|
30
|
+
play: () => boolean;
|
|
31
|
+
pause: () => void;
|
|
32
|
+
setValue: (path: string, value: boolean | number | string) => boolean;
|
|
33
|
+
trigger: (name: string) => boolean;
|
|
34
|
+
}
|
|
35
|
+
/** SDK is confined to this optional entry point; the consumer supplies its own licensed asset. */
|
|
36
|
+
export declare const createLumenRiveController: (options: LumenRiveOptions) => LumenRiveController;
|
|
37
|
+
//# sourceMappingURL=rive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rive.d.ts","sourceRoot":"","sources":["../src/rive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAI5D,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,WAAW,CAAA;AACzE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;IACpD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAClD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAClD,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,OAAO,EAAE,MAAM,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;CAC1D;AACD,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,8BAA8B,CAAC,GAAG;IACzG,QAAQ,CAAC,iBAAiB,EAAE,gBAAgB,GAAG,IAAI,CAAA;CACpD,CAAA;AACD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,EAAE,iBAAiB,CAAA;IACzB,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,cAAc,KAAK,gBAAgB,CAAA;IAChE,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAA;IAC5C,GAAG,EAAE,MAAM,CAAA;IACX,YAAY,EAAE,MAAM,CAAA;CACrB;AACD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,IAAI,EAAE,MAAM,OAAO,CAAA;IACnB,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,KAAK,OAAO,CAAA;IACrE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAA;CACnC;AA+BD,kGAAkG;AAClG,eAAO,MAAM,yBAAyB,GAAI,SAAS,gBAAgB,KAAG,mBA0IrE,CAAA"}
|
package/dist/rive.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Rive } from '@rive-app/canvas';
|
|
2
|
+
import { isLumenWorkflowMotionReduced } from './motion-workflows.js';
|
|
3
|
+
const observeRiveEnvironment = (canvas, resize, sync) => {
|
|
4
|
+
const view = canvas.ownerDocument.defaultView;
|
|
5
|
+
const media = view?.matchMedia('(prefers-reduced-motion: reduce)');
|
|
6
|
+
const resizeObserver = view?.ResizeObserver ? new view.ResizeObserver(resize) : undefined;
|
|
7
|
+
const motionObserver = view?.MutationObserver ? new view.MutationObserver(sync) : undefined;
|
|
8
|
+
resizeObserver?.observe(canvas);
|
|
9
|
+
motionObserver?.observe(canvas.ownerDocument.documentElement, {
|
|
10
|
+
attributes: true, attributeFilter: ['data-ui-motion'], subtree: true
|
|
11
|
+
});
|
|
12
|
+
media?.addEventListener('change', sync);
|
|
13
|
+
canvas.ownerDocument.addEventListener('visibilitychange', sync);
|
|
14
|
+
return () => {
|
|
15
|
+
resizeObserver?.disconnect();
|
|
16
|
+
motionObserver?.disconnect();
|
|
17
|
+
media?.removeEventListener('change', sync);
|
|
18
|
+
canvas.ownerDocument.removeEventListener('visibilitychange', sync);
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
const defaultRuntime = (parameters) => new Rive(parameters);
|
|
22
|
+
/** SDK is confined to this optional entry point; the consumer supplies its own licensed asset. */
|
|
23
|
+
export const createLumenRiveController = (options) => {
|
|
24
|
+
const { canvas, stateMachine } = options;
|
|
25
|
+
let runtime;
|
|
26
|
+
let destroyed = false;
|
|
27
|
+
let ready = false;
|
|
28
|
+
let requestedPlayback = options.autoplay === true;
|
|
29
|
+
let status = 'loading';
|
|
30
|
+
const notify = (next) => {
|
|
31
|
+
status = next;
|
|
32
|
+
options.onStatus?.(next);
|
|
33
|
+
};
|
|
34
|
+
const syncPlayback = () => {
|
|
35
|
+
if (!runtime || !ready || destroyed)
|
|
36
|
+
return;
|
|
37
|
+
const playing = requestedPlayback && !isLumenWorkflowMotionReduced(canvas) && !canvas.ownerDocument.hidden;
|
|
38
|
+
if (playing)
|
|
39
|
+
runtime.play(stateMachine);
|
|
40
|
+
else
|
|
41
|
+
runtime.pause(stateMachine);
|
|
42
|
+
};
|
|
43
|
+
const resize = () => {
|
|
44
|
+
if (!destroyed && ready)
|
|
45
|
+
runtime?.resizeDrawingSurfaceToCanvas();
|
|
46
|
+
};
|
|
47
|
+
const onLoad = () => {
|
|
48
|
+
queueMicrotask(() => {
|
|
49
|
+
if (destroyed || status === 'error')
|
|
50
|
+
return;
|
|
51
|
+
ready = true;
|
|
52
|
+
resize();
|
|
53
|
+
syncPlayback();
|
|
54
|
+
notify('ready');
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
const onError = () => {
|
|
58
|
+
if (destroyed)
|
|
59
|
+
return;
|
|
60
|
+
ready = false;
|
|
61
|
+
runtime?.pause(stateMachine);
|
|
62
|
+
notify('error');
|
|
63
|
+
};
|
|
64
|
+
const binding = () => ready && !destroyed ? runtime?.viewModelInstance : undefined;
|
|
65
|
+
notify('loading');
|
|
66
|
+
try {
|
|
67
|
+
runtime = (options.createRuntime ?? defaultRuntime)({
|
|
68
|
+
autoBind: true, autoplay: false, canvas, onLoad, onLoadError: onError, src: options.src, stateMachine
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
onError();
|
|
73
|
+
}
|
|
74
|
+
const cleanupEnvironment = observeRiveEnvironment(canvas, resize, syncPlayback);
|
|
75
|
+
return {
|
|
76
|
+
destroy: () => {
|
|
77
|
+
if (destroyed)
|
|
78
|
+
return;
|
|
79
|
+
destroyed = true;
|
|
80
|
+
cleanupEnvironment();
|
|
81
|
+
runtime?.cleanup();
|
|
82
|
+
runtime = undefined;
|
|
83
|
+
notify('destroyed');
|
|
84
|
+
},
|
|
85
|
+
pause: () => {
|
|
86
|
+
requestedPlayback = false;
|
|
87
|
+
syncPlayback();
|
|
88
|
+
},
|
|
89
|
+
play: () => {
|
|
90
|
+
requestedPlayback = true;
|
|
91
|
+
syncPlayback();
|
|
92
|
+
return ready && !destroyed && !isLumenWorkflowMotionReduced(canvas) && !canvas.ownerDocument.hidden;
|
|
93
|
+
},
|
|
94
|
+
setValue: (path, value) => {
|
|
95
|
+
const model = binding();
|
|
96
|
+
if (!model)
|
|
97
|
+
return false;
|
|
98
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
99
|
+
const property = model.number(path);
|
|
100
|
+
if (!property)
|
|
101
|
+
return false;
|
|
102
|
+
property.value = value;
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
if (typeof value === 'boolean') {
|
|
106
|
+
const property = model.boolean(path);
|
|
107
|
+
if (!property)
|
|
108
|
+
return false;
|
|
109
|
+
property.value = value;
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
if (typeof value === 'string') {
|
|
113
|
+
const property = model.string(path);
|
|
114
|
+
if (!property)
|
|
115
|
+
return false;
|
|
116
|
+
property.value = value;
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
},
|
|
121
|
+
trigger: path => {
|
|
122
|
+
const property = binding()?.trigger(path);
|
|
123
|
+
if (!property || isLumenWorkflowMotionReduced(canvas))
|
|
124
|
+
return false;
|
|
125
|
+
property.trigger();
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
};
|
package/dist/schedule.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../src/schedule.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,kBAAkB,EAAE,CAAA;IAC5B,QAAQ,CAAC,EAAE,qBAAqB,CAAA;CACjC;AAED,MAAM,WAAW,qBAAqB;IACpC,CAAC,EAAE,kBAAkB,CAAA;IACrB,CAAC,EAAE,kBAAkB,CAAA;CACtB;AAED,MAAM,MAAM,uBAAuB,GAAG,KAAK,GAAG,OAAO,CAAA;AAErD,MAAM,WAAW,0BAA0B;IACzC,IAAI,CAAC,EAAE,uBAAuB,CAAA;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,CAAA;CACxC;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CAC9C;AAED,MAAM,WAAW,4BAA6B,SAAQ,2BAA2B,EAAE,2BAA2B;CAAG;
|
|
1
|
+
{"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../src/schedule.ts"],"names":[],"mappings":"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"}
|
package/dist/schedule.js
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
const getScheduleRange = (event) => {
|
|
2
|
+
const start = new Date(event.start).getTime();
|
|
3
|
+
const end = new Date(event.end).getTime();
|
|
4
|
+
return Number.isFinite(start) && Number.isFinite(end) && start <= end ? { end, start } : undefined;
|
|
5
|
+
};
|
|
6
|
+
const requireScheduleTime = (value, field) => {
|
|
7
|
+
const time = new Date(value).getTime();
|
|
8
|
+
if (!Number.isFinite(time))
|
|
9
|
+
throw new TypeError(`Schedule ${field} must be a valid date-time.`);
|
|
10
|
+
return time;
|
|
11
|
+
};
|
|
12
|
+
const requireScheduleRange = (event) => {
|
|
13
|
+
const range = getScheduleRange(event);
|
|
14
|
+
if (!range)
|
|
15
|
+
throw new TypeError('Schedule event must have valid date-times with start no later than end.');
|
|
16
|
+
return range;
|
|
17
|
+
};
|
|
1
18
|
export const createScheduleSlots = (dates, events, resources = []) => {
|
|
2
19
|
const resourceList = resources.length ? resources : [undefined];
|
|
3
20
|
return dates.flatMap(date => resourceList.map(resource => ({
|
|
@@ -15,22 +32,38 @@ export const moveScheduleEvent = (events, eventId, nextStart, nextEnd, resourceI
|
|
|
15
32
|
start: nextStart
|
|
16
33
|
} :
|
|
17
34
|
event);
|
|
18
|
-
export const expandRecurringScheduleEvent = (event, count, intervalDays = 7) =>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
start
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
export const expandRecurringScheduleEvent = (event, count, intervalDays = 7) => {
|
|
36
|
+
if (!Number.isSafeInteger(count) || count < 0)
|
|
37
|
+
throw new RangeError('Schedule recurrence count must be a non-negative safe integer.');
|
|
38
|
+
if (!Number.isFinite(intervalDays))
|
|
39
|
+
throw new RangeError('Schedule recurrence interval must be finite.');
|
|
40
|
+
if (count === 0)
|
|
41
|
+
return [];
|
|
42
|
+
const range = requireScheduleRange(event);
|
|
43
|
+
return Array.from({ length: count }, (_, index) => {
|
|
44
|
+
const start = new Date(range.start);
|
|
45
|
+
const end = new Date(range.end);
|
|
46
|
+
start.setUTCDate(start.getUTCDate() + index * intervalDays);
|
|
47
|
+
end.setUTCDate(end.getUTCDate() + index * intervalDays);
|
|
48
|
+
if (!Number.isFinite(start.getTime()) || !Number.isFinite(end.getTime())) {
|
|
49
|
+
throw new RangeError('Schedule recurrence exceeds the supported date-time range.');
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
...event,
|
|
53
|
+
end: end.toISOString(),
|
|
54
|
+
id: index === 0 ? event.id : `${event.id}-${index + 1}`,
|
|
55
|
+
start: start.toISOString()
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
export const scheduleEventsOverlap = (a, b) => {
|
|
60
|
+
if (a.id === b.id || (a.resourceId && b.resourceId && a.resourceId !== b.resourceId))
|
|
61
|
+
return false;
|
|
62
|
+
const first = getScheduleRange(a);
|
|
63
|
+
const second = getScheduleRange(b);
|
|
64
|
+
// An invalid interval cannot establish availability for a shared resource.
|
|
65
|
+
return !first || !second || (first.start < second.end && second.start < first.end);
|
|
66
|
+
};
|
|
34
67
|
export const getScheduleConflicts = (events) => {
|
|
35
68
|
const conflicts = [];
|
|
36
69
|
for (const [index, event] of events.entries()) {
|
|
@@ -42,20 +75,27 @@ export const getScheduleConflicts = (events) => {
|
|
|
42
75
|
}
|
|
43
76
|
return conflicts;
|
|
44
77
|
};
|
|
45
|
-
export const canPlaceScheduleEvent = (events, event) => !events.some(nextEvent => scheduleEventsOverlap(event, nextEvent));
|
|
78
|
+
export const canPlaceScheduleEvent = (events, event) => Boolean(getScheduleRange(event)) && !events.some(nextEvent => scheduleEventsOverlap(event, nextEvent));
|
|
46
79
|
const clampTime = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
47
80
|
const snapTime = (value, snapMinutes = 15) => {
|
|
81
|
+
if (!Number.isFinite(snapMinutes))
|
|
82
|
+
throw new RangeError('Schedule snap minutes must be finite.');
|
|
48
83
|
const snapMs = Math.max(1, snapMinutes) * 60_000;
|
|
49
|
-
|
|
84
|
+
const snapped = Math.round(value / snapMs) * snapMs;
|
|
85
|
+
if (!Number.isFinite(snapped) || Math.abs(snapped) > 8.64e15) {
|
|
86
|
+
throw new RangeError('Schedule snapped time exceeds the supported date-time range.');
|
|
87
|
+
}
|
|
88
|
+
return snapped;
|
|
50
89
|
};
|
|
51
90
|
const minScheduleEventDurationMs = 60_000;
|
|
52
91
|
export const resizeScheduleEvent = (event, nextDateTime, options = {}) => {
|
|
53
92
|
const edge = options.edge ?? 'end';
|
|
54
|
-
const start =
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
93
|
+
const { start, end } = requireScheduleRange(event);
|
|
94
|
+
const minBound = options.min !== undefined ? requireScheduleTime(options.min, 'minimum') : -Infinity;
|
|
95
|
+
const maxBound = options.max !== undefined ? requireScheduleTime(options.max, 'maximum') : Infinity;
|
|
96
|
+
if (minBound > maxBound)
|
|
97
|
+
throw new RangeError('Schedule minimum cannot exceed maximum.');
|
|
98
|
+
const snapped = snapTime(requireScheduleTime(nextDateTime, 'resize target'), options.snapMinutes);
|
|
59
99
|
// The explicit min/max bound is a hard caller contract (for example a visible
|
|
60
100
|
// drag range) and must never be exceeded; the minimum duration is only a
|
|
61
101
|
// best-effort safety net and yields to that bound when the two conflict
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tab-indicator.d.ts","sourceRoot":"","sources":["../src/tab-indicator.ts"],"names":[],"mappings":"AAEA,kGAAkG;AAClG,eAAO,MAAM,qBAAqB,GAAI,MAAM,WAAW,KAAG,CAAC,MAAM,IAAI,CAqFpE,CAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { getLumenWorkflowTiming, isLumenWorkflowMotionReduced } from './motion-workflows.js';
|
|
2
|
+
/** Decorative selection marker; existing tabs retain keyboard, focus, and selection ownership. */
|
|
3
|
+
export const bindLumenTabIndicator = (root) => {
|
|
4
|
+
const list = root.querySelector('[role="tablist"]');
|
|
5
|
+
const view = root.ownerDocument.defaultView;
|
|
6
|
+
if (!list || !view)
|
|
7
|
+
return () => undefined;
|
|
8
|
+
const indicator = root.ownerDocument.createElement('span');
|
|
9
|
+
indicator.className = 'ui-tabs__moving-indicator';
|
|
10
|
+
indicator.setAttribute('aria-hidden', 'true');
|
|
11
|
+
const originalPosition = list.style.position;
|
|
12
|
+
if (view.getComputedStyle(list).position === 'static')
|
|
13
|
+
list.style.position = 'relative';
|
|
14
|
+
let frame;
|
|
15
|
+
let initialized = false;
|
|
16
|
+
const sync = () => {
|
|
17
|
+
frame = undefined;
|
|
18
|
+
const selected = list.querySelector('[role="tab"][aria-selected="true"]');
|
|
19
|
+
indicator.hidden = !selected;
|
|
20
|
+
if (!selected)
|
|
21
|
+
return;
|
|
22
|
+
const bounds = selected.getBoundingClientRect();
|
|
23
|
+
const container = list.getBoundingClientRect();
|
|
24
|
+
const timing = getLumenWorkflowTiming(root);
|
|
25
|
+
const duration = initialized && !isLumenWorkflowMotionReduced(root) ? timing.duration : 0;
|
|
26
|
+
indicator.style.transition = `translate ${duration}ms ${timing.easing}, width ${duration}ms ${timing.easing}`;
|
|
27
|
+
const vertical = list.getAttribute('aria-orientation') === 'vertical';
|
|
28
|
+
indicator.style.width = vertical ? '2px' : `${bounds.width}px`;
|
|
29
|
+
indicator.style.height = vertical ? `${bounds.height}px` : '2px';
|
|
30
|
+
indicator.style.top = vertical ? '0' : '';
|
|
31
|
+
indicator.style.bottom = vertical ? 'auto' : '0';
|
|
32
|
+
indicator.style.translate = vertical ?
|
|
33
|
+
`0 ${bounds.top - container.top + list.scrollTop}px` :
|
|
34
|
+
`${bounds.left - container.left + list.scrollLeft}px 0`;
|
|
35
|
+
initialized = true;
|
|
36
|
+
};
|
|
37
|
+
const schedule = () => {
|
|
38
|
+
frame ??= view.requestAnimationFrame(sync);
|
|
39
|
+
};
|
|
40
|
+
const observer = new view.MutationObserver(schedule);
|
|
41
|
+
observer.observe(root, { subtree: true, attributes: true, attributeFilter: ['aria-selected', 'aria-orientation', 'data-ui-motion'] });
|
|
42
|
+
const resize = typeof view.ResizeObserver === 'function' ? new view.ResizeObserver(schedule) : undefined;
|
|
43
|
+
resize?.observe(list);
|
|
44
|
+
const media = view.matchMedia('(prefers-reduced-motion: reduce)');
|
|
45
|
+
media.addEventListener('change', schedule);
|
|
46
|
+
list.append(indicator);
|
|
47
|
+
sync();
|
|
48
|
+
return () => {
|
|
49
|
+
observer.disconnect();
|
|
50
|
+
resize?.disconnect();
|
|
51
|
+
media.removeEventListener('change', schedule);
|
|
52
|
+
if (frame !== undefined)
|
|
53
|
+
view.cancelAnimationFrame(frame);
|
|
54
|
+
indicator.remove();
|
|
55
|
+
list.style.position = originalPosition;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type LumenThemeTokens } from './theme.js';
|
|
2
|
+
export interface LumenThemeAuditFinding {
|
|
3
|
+
rule: 'missing-token' | 'unresolved-color' | 'text-contrast';
|
|
4
|
+
tokens: readonly string[];
|
|
5
|
+
message: string;
|
|
6
|
+
ratio?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface LumenThemeAudit {
|
|
9
|
+
findings: LumenThemeAuditFinding[];
|
|
10
|
+
healthy: boolean;
|
|
11
|
+
}
|
|
12
|
+
/** No default palette is injected: a missing or unresolved mapping cannot pass contrast. */
|
|
13
|
+
export declare const auditLumenTheme: (tokens: Readonly<LumenThemeTokens>) => LumenThemeAudit;
|
|
14
|
+
/** Run once per representative light, dark and nested scope after its theme is applied. */
|
|
15
|
+
export declare const inspectLumenTheme: (scope: Element) => LumenThemeAudit;
|
|
16
|
+
//# sourceMappingURL=theme-audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-audit.d.ts","sourceRoot":"","sources":["../src/theme-audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkD,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElG,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,eAAe,GAAG,kBAAkB,GAAG,eAAe,CAAA;IAC5D,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,sBAAsB,EAAE,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;CACjB;AA2CD,4FAA4F;AAC5F,eAAO,MAAM,eAAe,GAAI,QAAQ,QAAQ,CAAC,gBAAgB,CAAC,KAAG,eAepE,CAAA;AAED,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,eASlD,CAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { getContrastRatio, lumenSemanticColorTokenNames } from './theme.js';
|
|
2
|
+
const pairs = [
|
|
3
|
+
['ink', 'canvas'],
|
|
4
|
+
['ink', 'surface'],
|
|
5
|
+
['ink', 'surface-muted'],
|
|
6
|
+
['ink-soft', 'surface'],
|
|
7
|
+
['ink-muted', 'surface'],
|
|
8
|
+
['on-brand', 'brand-solid'],
|
|
9
|
+
['on-danger', 'danger']
|
|
10
|
+
];
|
|
11
|
+
const opaqueChannels = (value) => {
|
|
12
|
+
const parts = value.trim().split(/\s+/u);
|
|
13
|
+
if (parts.length !== 3)
|
|
14
|
+
return false;
|
|
15
|
+
const [hue = '', saturation = '', lightness = ''] = parts;
|
|
16
|
+
const numeric = (part) => /^-?\d+(?:\.\d+)?$/u.test(part);
|
|
17
|
+
const percent = (part) => part.endsWith('%') && numeric(part.slice(0, -1)) && Number(part.slice(0, -1)) >= 0 && Number(part.slice(0, -1)) <= 100;
|
|
18
|
+
return numeric(hue) && Number.isFinite(Number(hue)) && percent(saturation) && percent(lightness);
|
|
19
|
+
};
|
|
20
|
+
const contrastFindings = (tokens, readable) => {
|
|
21
|
+
const findings = [];
|
|
22
|
+
for (const [foreground, background] of pairs) {
|
|
23
|
+
const ink = tokens[foreground];
|
|
24
|
+
const surface = tokens[background];
|
|
25
|
+
if (!ink || !surface || !readable.has(foreground) || !readable.has(background))
|
|
26
|
+
continue;
|
|
27
|
+
const ratio = getContrastRatio(ink, surface);
|
|
28
|
+
if (ratio < 4.5)
|
|
29
|
+
findings.push({ rule: 'text-contrast', tokens: [foreground, background], ratio, message: `--${foreground} on --${background} has ${ratio}:1 contrast; normal text requires 4.5:1.` });
|
|
30
|
+
}
|
|
31
|
+
return findings;
|
|
32
|
+
};
|
|
33
|
+
/** No default palette is injected: a missing or unresolved mapping cannot pass contrast. */
|
|
34
|
+
export const auditLumenTheme = (tokens) => {
|
|
35
|
+
const findings = [];
|
|
36
|
+
const readable = new Set();
|
|
37
|
+
for (const token of lumenSemanticColorTokenNames) {
|
|
38
|
+
const value = tokens[token]?.trim();
|
|
39
|
+
if (!value)
|
|
40
|
+
findings.push({ rule: 'missing-token', tokens: [token], message: `Missing semantic mapping --${token}.` });
|
|
41
|
+
else if (!opaqueChannels(value))
|
|
42
|
+
findings.push({ rule: 'unresolved-color', tokens: [token], message: `--${token} needs resolved opaque HSL channels for this contrast check.` });
|
|
43
|
+
else
|
|
44
|
+
readable.add(token);
|
|
45
|
+
}
|
|
46
|
+
findings.push(...contrastFindings(tokens, readable));
|
|
47
|
+
return { findings, healthy: findings.length === 0 };
|
|
48
|
+
};
|
|
49
|
+
/** Run once per representative light, dark and nested scope after its theme is applied. */
|
|
50
|
+
export const inspectLumenTheme = (scope) => {
|
|
51
|
+
const view = scope.ownerDocument.defaultView;
|
|
52
|
+
if (!view)
|
|
53
|
+
throw new Error('Theme inspection requires a document with a window.');
|
|
54
|
+
const style = view.getComputedStyle(scope);
|
|
55
|
+
const tokens = Object.fromEntries(lumenSemanticColorTokenNames.map(token => [token, style.getPropertyValue(`--${token}`).trim()]));
|
|
56
|
+
return auditLumenTheme(tokens);
|
|
57
|
+
};
|
package/dist/theme-builder.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { type LumenThemeTokens } from './theme.js';
|
|
1
|
+
import { type LumenThemePreset, type LumenThemeTokens } from './theme.js';
|
|
2
2
|
export type LumenThemeBuilderExportFormat = 'css' | 'figma' | 'tokens';
|
|
3
3
|
export type LumenThemeBuilderMode = 'generated' | 'manual';
|
|
4
4
|
export type LumenThemeBuilderScheme = 'dark' | 'light';
|
|
5
5
|
export interface LumenThemeBuilderOptions {
|
|
6
|
+
radiusScale?: number | string | null;
|
|
7
|
+
spacingScale?: number | string | null;
|
|
8
|
+
borderWidth?: number | string | null;
|
|
9
|
+
preset?: string | null;
|
|
6
10
|
accentHue?: number | string | null;
|
|
7
11
|
hue?: number | string | null;
|
|
8
12
|
mode?: string | null;
|
|
@@ -11,12 +15,14 @@ export interface LumenThemeBuilderOptions {
|
|
|
11
15
|
secondaryColor?: string | null;
|
|
12
16
|
}
|
|
13
17
|
export interface LumenThemeBuilderResult {
|
|
18
|
+
preset?: LumenThemePreset;
|
|
14
19
|
accentHue: number;
|
|
15
20
|
hue: number;
|
|
16
21
|
mode: LumenThemeBuilderMode;
|
|
17
22
|
scheme: LumenThemeBuilderScheme;
|
|
18
23
|
tokens: LumenThemeTokens;
|
|
19
24
|
}
|
|
25
|
+
export declare const coerceThemePreset: (value?: string | null) => LumenThemePreset;
|
|
20
26
|
export declare const coerceThemeBuilderExportFormat: (value?: string | null) => LumenThemeBuilderExportFormat;
|
|
21
27
|
export declare const coerceThemeBuilderMode: (value?: string | null) => LumenThemeBuilderMode;
|
|
22
28
|
export declare const coerceThemeBuilderScheme: (value?: string | null) => LumenThemeBuilderScheme;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-builder.d.ts","sourceRoot":"","sources":["../src/theme-builder.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"theme-builder.d.ts","sourceRoot":"","sources":["../src/theme-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE3C,MAAM,MAAM,6BAA6B,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEtE,MAAM,MAAM,qBAAqB,GAAG,WAAW,GAAG,QAAQ,CAAA;AAE1D,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,OAAO,CAAA;AAEtD,MAAM,WAAW,wBAAwB;IACvC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACpC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACrC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACpC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAClC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAC5B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B;AA8BD,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,gBAAgB,CAAA;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,qBAAqB,CAAA;IAC3B,MAAM,EAAE,uBAAuB,CAAA;IAC/B,MAAM,EAAE,gBAAgB,CAAA;CACzB;AAED,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,GAAG,IAAI,KAAG,gBAA+E,CAAA;AAEzI,eAAO,MAAM,8BAA8B,GACzC,QAAQ,MAAM,GAAG,IAAI,KACpB,6BAIF,CAAA;AAED,eAAO,MAAM,sBAAsB,GACjC,QAAQ,MAAM,GAAG,IAAI,KACpB,qBAAsE,CAAA;AAEzE,eAAO,MAAM,wBAAwB,GACnC,QAAQ,MAAM,GAAG,IAAI,KACpB,uBAAgE,CAAA;AAEnE,eAAO,MAAM,wBAAwB,GACnC,OAAO,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EACzC,iBAAY,KACX,MAMF,CAAA;AAED,eAAO,MAAM,wBAAwB,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,IAcjE,CAAA;AAED,eAAO,MAAM,oBAAoB,GAC/B,OAAO,MAAM,KACZ;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAiCnC,CAAA;AAoBD,eAAO,MAAM,wBAAwB,GACnC,UAAS,wBAA6B,KACrC,uBAgCF,CAAA;AAED,eAAO,MAAM,qBAAqB,GAChC,QAAQ,gBAAgB,EACxB,QAAQ,uBAAuB,KAC9B,MAOF,CAAA;AAED,eAAO,MAAM,uBAAuB,GAClC,QAAQ,gBAAgB,EACxB,QAAQ,uBAAuB,EAC/B,QAAQ,6BAA6B,KACpC,MAeF,CAAA"}
|