@hashicorp/design-system-components 5.1.1-rc-20251209143536 → 5.2.0-rc-20251216140614
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/declarations/components/hds/breadcrumb/item.d.ts +4 -8
- package/declarations/components/hds/dropdown/index.d.ts +2 -0
- package/declarations/components/hds/icon/index.d.ts +1 -1
- package/declarations/components/hds/interactive/index.d.ts +4 -9
- package/declarations/components/hds/popover-primitive/index.d.ts +2 -0
- package/declarations/components/hds/rich-tooltip/bubble.d.ts +2 -0
- package/declarations/components/hds/stepper/task/indicator.d.ts +1 -1
- package/declarations/components/hds/theme-context/index.d.ts +24 -0
- package/declarations/components/hds/theme-context/types.d.ts +19 -0
- package/declarations/components/hds/theme-switcher/index.d.ts +43 -0
- package/declarations/components.d.ts +2 -0
- package/declarations/modifiers/hds-anchored-position.d.ts +3 -1
- package/declarations/services/hds-theming.d.ts +57 -0
- package/declarations/services.d.ts +1 -0
- package/declarations/template-registry.d.ts +6 -0
- package/declarations/utils/hds-resolve-link-to-external.d.ts +12 -0
- package/dist/_app_/components/hds/theme-context.js +1 -0
- package/dist/_app_/components/hds/theme-switcher.js +1 -0
- package/dist/_app_/services/hds-theming.js +1 -0
- package/dist/components/hds/breadcrumb/item.js +17 -15
- package/dist/components/hds/breadcrumb/item.js.map +1 -1
- package/dist/components/hds/dropdown/index.js +3 -2
- package/dist/components/hds/dropdown/index.js.map +1 -1
- package/dist/components/hds/interactive/index.js +17 -19
- package/dist/components/hds/interactive/index.js.map +1 -1
- package/dist/components/hds/popover-primitive/index.js +1 -1
- package/dist/components/hds/popover-primitive/index.js.map +1 -1
- package/dist/components/hds/rich-tooltip/bubble.js +2 -1
- package/dist/components/hds/rich-tooltip/bubble.js.map +1 -1
- package/dist/components/hds/theme-context/index.js +45 -0
- package/dist/components/hds/theme-context/index.js.map +1 -0
- package/dist/components/hds/theme-context/types.js +27 -0
- package/dist/components/hds/theme-context/types.js.map +1 -0
- package/dist/components/hds/theme-switcher/index.js +100 -0
- package/dist/components/hds/theme-switcher/index.js.map +1 -0
- package/dist/components.js +2 -0
- package/dist/components.js.map +1 -1
- package/dist/modifiers/hds-anchored-position.js +42 -4
- package/dist/modifiers/hds-anchored-position.js.map +1 -1
- package/dist/services/hds-theming.js +214 -0
- package/dist/services/hds-theming.js.map +1 -0
- package/dist/services.js +1 -1
- package/dist/styles/@hashicorp/design-system-components-common.css +9584 -0
- package/dist/styles/@hashicorp/design-system-components-common.css.map +1 -0
- package/dist/styles/@hashicorp/design-system-components-common.scss +24 -0
- package/dist/styles/@hashicorp/design-system-components.css +544 -337
- package/dist/styles/@hashicorp/design-system-components.css.map +1 -0
- package/dist/styles/@hashicorp/design-system-components.scss +4 -62
- package/dist/styles/@hashicorp/design-system-power-select-overrides.css +229 -0
- package/dist/styles/@hashicorp/design-system-power-select-overrides.css.map +1 -0
- package/dist/styles/components/badge-count.scss +26 -76
- package/dist/styles/components/badge.scss +26 -131
- package/dist/styles/components/button.scss +5 -0
- package/dist/styles/components/dropdown.scss +3 -5
- package/dist/styles/components/form/file-input.scss +2 -2
- package/dist/styles/components/form/key-value-inputs.scss +2 -4
- package/dist/styles/components/form/super-select.scss +12 -4
- package/dist/styles/components/index.scss +52 -0
- package/dist/styles/components/theme-context.scss +12 -0
- package/dist/styles/mixins/_button.scss +82 -129
- package/dist/styles/mixins/_carbonization.scss +31 -0
- package/dist/styles/mixins/_interactive-dark-theme.scss +1 -1
- package/dist/utils/hds-resolve-link-to-external.js +33 -0
- package/dist/utils/hds-resolve-link-to-external.js.map +1 -0
- package/package.json +12 -4
- package/dist/styles/@hashicorp/design-system-components.scss.map +0 -1
|
@@ -21,6 +21,21 @@ const ENABLE_COLLISION_DETECTION_OPTIONS = Object.values(HdsEnableCollisionDetec
|
|
|
21
21
|
// this refers to the minimum distance from the boundaries' edges (the viewport)
|
|
22
22
|
// before the floating element changes its position (flips, shifts, or autoplace itself)
|
|
23
23
|
const DEFAULT_EDGE_DISTANCE = 8;
|
|
24
|
+
// resolve boundary selector/values to Floating UI Boundary
|
|
25
|
+
const resolveBoundary = boundary => {
|
|
26
|
+
if (typeof boundary === 'string') {
|
|
27
|
+
// this is necessary to satisfy TypeScript
|
|
28
|
+
if (boundary === 'clippingAncestors') {
|
|
29
|
+
return 'clippingAncestors';
|
|
30
|
+
}
|
|
31
|
+
const el = document.querySelector(boundary);
|
|
32
|
+
assert('`hds-anchored-position` modifier - the `boundary` selector `' + boundary + '` did not resolve to an element', el !== null && el.nodeType === Node.ELEMENT_NODE);
|
|
33
|
+
return el;
|
|
34
|
+
} else {
|
|
35
|
+
return boundary;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
24
39
|
// we use this function to process all the options provided to the modifier in a single place,
|
|
25
40
|
// in relation to the Floating UI APIs, and keep the modifier code more clean/simple
|
|
26
41
|
const getFloatingUIOptions = options => {
|
|
@@ -43,8 +58,31 @@ const getFloatingUIOptions = options => {
|
|
|
43
58
|
enableCollisionDetection,
|
|
44
59
|
arrowElement,
|
|
45
60
|
arrowPadding,
|
|
46
|
-
matchToggleWidth
|
|
61
|
+
matchToggleWidth,
|
|
62
|
+
boundary
|
|
47
63
|
} = options;
|
|
64
|
+
const resolvedBoundary = resolveBoundary(boundary);
|
|
65
|
+
|
|
66
|
+
// build options for each type of collision detection, adding the `boundary` if defined
|
|
67
|
+
|
|
68
|
+
const flipOptsExtended = {
|
|
69
|
+
...flipOptions,
|
|
70
|
+
...(resolvedBoundary ? {
|
|
71
|
+
boundary: resolvedBoundary
|
|
72
|
+
} : {})
|
|
73
|
+
};
|
|
74
|
+
const autoPlacementOptsExtended = {
|
|
75
|
+
...autoPlacementOptions,
|
|
76
|
+
...(resolvedBoundary ? {
|
|
77
|
+
boundary: resolvedBoundary
|
|
78
|
+
} : {})
|
|
79
|
+
};
|
|
80
|
+
const shiftOptsExtended = {
|
|
81
|
+
...shiftOptions,
|
|
82
|
+
...(resolvedBoundary ? {
|
|
83
|
+
boundary: resolvedBoundary
|
|
84
|
+
} : {})
|
|
85
|
+
};
|
|
48
86
|
|
|
49
87
|
// we build dynamically the list of middleware functions to invoke, depending on the options provided
|
|
50
88
|
|
|
@@ -57,13 +95,13 @@ const getFloatingUIOptions = options => {
|
|
|
57
95
|
// https://floating-ui.com/docs/shift
|
|
58
96
|
// https://floating-ui.com/docs/autoPlacement
|
|
59
97
|
if (enableCollisionDetection === true || enableCollisionDetection === 'flip') {
|
|
60
|
-
middleware.push(flip(
|
|
98
|
+
middleware.push(flip(flipOptsExtended));
|
|
61
99
|
}
|
|
62
100
|
if (enableCollisionDetection === true || enableCollisionDetection === 'shift') {
|
|
63
|
-
middleware.push(shift(
|
|
101
|
+
middleware.push(shift(shiftOptsExtended));
|
|
64
102
|
}
|
|
65
103
|
if (enableCollisionDetection === 'auto') {
|
|
66
|
-
middleware.push(autoPlacement(
|
|
104
|
+
middleware.push(autoPlacement(autoPlacementOptsExtended));
|
|
67
105
|
}
|
|
68
106
|
|
|
69
107
|
// https://floating-ui.com/docs/arrow
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hds-anchored-position.js","sources":["../../src/modifiers/hds-anchored-position.ts"],"sourcesContent":["/**\n * Copyright IBM Corp. 2021, 2025\n * SPDX-License-Identifier: MPL-2.0\n */\n\nimport { modifier } from 'ember-modifier';\nimport { assert } from '@ember/debug';\n\nimport {\n autoUpdate,\n computePosition,\n offset,\n flip,\n shift,\n limitShift,\n autoPlacement,\n arrow,\n // ---\n // this could be used in the future if we want to give consumers an option to hide the \"floating\" element when the \"anchor\" hides from the viewport\n // see: https://floating-ui.com/docs/hide\n // hide,\n // ---\n size,\n} from '@floating-ui/dom';\n\nimport type {\n Placement,\n Strategy,\n OffsetOptions,\n FlipOptions,\n ShiftOptions,\n AutoPlacementOptions,\n ArrowOptions,\n Middleware,\n} from '@floating-ui/dom';\n\nexport enum HdsEnableCollisionDetectionOptions {\n Shift = 'shift',\n Flip = 'flip',\n Auto = 'auto',\n}\n\nexport type HdsEnableCollisionDetection =\n `${HdsEnableCollisionDetectionOptions}`;\n\nexport const DEFAULT_PLACEMENT = 'bottom';\nexport const PLACEMENTS: Placement[] = [\n 'top',\n 'top-start',\n 'top-end',\n 'right',\n 'right-start',\n 'right-end',\n 'bottom',\n 'bottom-start',\n 'bottom-end',\n 'left',\n 'left-start',\n 'left-end',\n];\n\nexport const ENABLE_COLLISION_DETECTION_OPTIONS: HdsEnableCollisionDetection[] =\n Object.values(HdsEnableCollisionDetectionOptions);\n\n// share the same default value of \"padding\" for `flip/shift/autoPlacement` options\n// this refers to the minimum distance from the boundaries' edges (the viewport)\n// before the floating element changes its position (flips, shifts, or autoplace itself)\nconst DEFAULT_EDGE_DISTANCE = 8;\n\nexport type FloatingUIOptions = {\n placement?: Placement;\n strategy?: Strategy;\n offsetOptions?: OffsetOptions;\n flipOptions?: FlipOptions;\n shiftOptions?: ShiftOptions;\n autoPlacementOptions?: AutoPlacementOptions;\n middlewareExtra?: Middleware[];\n enableCollisionDetection?: boolean | HdsEnableCollisionDetection;\n arrowElement?: ArrowOptions['element'];\n arrowPadding?: ArrowOptions['padding'];\n matchToggleWidth?: boolean;\n};\n\nexport type HdsAnchoredPositionOptions = FloatingUIOptions & {\n arrowSelector?: string;\n};\n\n// we use this function to process all the options provided to the modifier in a single place,\n// in relation to the Floating UI APIs, and keep the modifier code more clean/simple\nexport const getFloatingUIOptions = (\n options: FloatingUIOptions\n): {\n placement: Placement;\n strategy: Strategy;\n middleware: Middleware[];\n} => {\n const {\n placement = DEFAULT_PLACEMENT,\n strategy = 'absolute', // we don't need to use `fixed` if we use the Popover API for the \"floating\" element (it puts the element in the `top-layer`)\n offsetOptions,\n flipOptions = { padding: DEFAULT_EDGE_DISTANCE },\n shiftOptions = { padding: DEFAULT_EDGE_DISTANCE, limiter: limitShift() },\n autoPlacementOptions = { padding: DEFAULT_EDGE_DISTANCE },\n middlewareExtra = [],\n enableCollisionDetection,\n arrowElement,\n arrowPadding,\n matchToggleWidth,\n } = options;\n\n // we build dynamically the list of middleware functions to invoke, depending on the options provided\n\n const middleware = [];\n\n // https://floating-ui.com/docs/offset\n middleware.push(offset(offsetOptions));\n\n // https://floating-ui.com/docs/flip\n // https://floating-ui.com/docs/shift\n // https://floating-ui.com/docs/autoPlacement\n if (\n enableCollisionDetection === true ||\n enableCollisionDetection === 'flip'\n ) {\n middleware.push(flip(flipOptions));\n }\n if (\n enableCollisionDetection === true ||\n enableCollisionDetection === 'shift'\n ) {\n middleware.push(shift(shiftOptions));\n }\n if (enableCollisionDetection === 'auto') {\n middleware.push(autoPlacement(autoPlacementOptions));\n }\n\n // https://floating-ui.com/docs/arrow\n if (arrowElement) {\n middleware.push(\n arrow({\n element: arrowElement,\n padding: arrowPadding ?? 0,\n })\n );\n }\n\n // https://floating-ui.com/docs/size#match-reference-width\n if (matchToggleWidth) {\n middleware.push(\n size({\n apply({ rects, elements }) {\n // wrap Object.assign inside a requestAnimationFrame to avoid ResizeObserver loop limit exceeded error\n // https://github.com/floating-ui/floating-ui/issues/1740\n requestAnimationFrame(() => {\n Object.assign(elements.floating.style, {\n width: `${rects.reference.width}px`,\n });\n });\n },\n })\n );\n }\n\n middleware.push(...middlewareExtra);\n\n return {\n placement,\n strategy,\n middleware,\n };\n};\n\nexport interface HdsAnchoredPositionSignature {\n Element: HTMLElement;\n Args: {\n Positional: [HTMLElement | SVGElement];\n Named: HdsAnchoredPositionOptions;\n };\n}\n\n// Notice: we use a function-based modifier here instead of a class-based one\n// because it's quite simple in its logic, and doesn't require injecting services\n// see: https://github.com/ember-modifier/ember-modifier#function-based-modifiers\n\nexport default modifier<HdsAnchoredPositionSignature>(\n (element, positional, named = {}) => {\n // the element that \"floats\" next to the \"anchor\" (whose position is calculated in relation to the anchor)\n // notice: this is the element the Ember modifier is attached to\n const _floatingElement = element;\n\n // the element that acts as an \"anchor\" for the \"floating\" element\n // it can be a DOM (string) selector or a DOM element\n // notice: it's expressed as \"positional\" argument (array of arguments) for the modifier\n const _anchorTarget = positional[0];\n const _anchorElement =\n typeof _anchorTarget === 'string'\n ? document.querySelector(_anchorTarget)\n : _anchorTarget;\n\n assert(\n '`hds-anchored-position` modifier - the provided \"anchoring\" element is not defined correctly',\n _anchorElement instanceof HTMLElement ||\n _anchorElement instanceof SVGElement\n );\n\n // the \"arrow\" element (optional) associated with the \"floating\" element\n // it can be a DOM selector (string) or a DOM element\n // notice: it's declared inside the \"named\" argument (object) for the modifier\n // but we need to extract it also here so it can be used to assign inline styles to it\n let arrowElement: HTMLElement | SVGElement | undefined;\n\n if (named.arrowElement) {\n assert(\n '`hds-anchored-position` modifier - the `element` provided for the \"arrow\" element is not a valid DOM node',\n named.arrowElement instanceof HTMLElement ||\n named.arrowElement instanceof SVGElement\n );\n\n arrowElement = named.arrowElement;\n } else if (named.arrowSelector) {\n assert(\n '`hds-anchored-position` modifier - the `selector` provided for the \"arrow\" element must be a string',\n typeof named.arrowSelector === 'string'\n );\n\n const selectedArrowElement = document.querySelector(named.arrowSelector);\n if (selectedArrowElement instanceof HTMLElement) {\n arrowElement = selectedArrowElement;\n } else {\n assert(\n '`hds-anchored-position` modifier - the `selector` provided for the \"arrow\" element is not a valid DOM selector'\n );\n }\n }\n\n // the Floating UI \"options\" to apply to the \"floating\" element\n // notice: we spread the `named` argument and override its `arrowElement` value instead of setting it directly because Ember complains that modifier's arguments must be immutable\n const floatingOptions = getFloatingUIOptions({ ...named, arrowElement });\n\n const computeFloatingPosition = async () => {\n // important to know: `computePosition()` is not stateful, it only positions the \"floating\" element once\n // see: https://floating-ui.com/docs/computePosition\n const state = await computePosition(\n _anchorElement,\n _floatingElement,\n floatingOptions\n );\n\n const { x, y, placement, strategy, middlewareData } = state;\n\n Object.assign(_floatingElement.style, {\n position: strategy,\n top: `${y}px`,\n left: `${x}px`,\n // TODO? commenting this for now, will need to make this conditional to some argument (and understand how this relates to the `@height` argument)\n // maxHeight: `${middlewareData.size.availableHeight - 10}px`,\n });\n\n if (arrowElement && middlewareData.arrow) {\n // we assign a \"data\" attribute to the \"arrow\" element so we can use CSS (in the consuming components) to position/rotate it accordingly and we avoid calculating at runtime values that technically we already know\n // (similar to what Tippy.js does: https://github.com/atomiks/tippyjs/blob/master/src/scss/svg-arrow.scss)\n // IMPORTANT: floating-ui assumes the \"arrow\" container is square!\n arrowElement.setAttribute(\n 'data-hds-anchored-arrow-placement',\n placement\n );\n\n // we set `x` or `y` value (depends on the position of the arrow in relation to the \"floating\" element placement)\n // see: https://floating-ui.com/docs/arrow#usage\n Object.assign(arrowElement.style, {\n left:\n middlewareData.arrow.x != null ? `${middlewareData.arrow.x}px` : '',\n top:\n middlewareData.arrow.y != null ? `${middlewareData.arrow.y}px` : '',\n });\n }\n };\n\n // the `autoUpdate` function automatically updates the position of the floating element when necessary.\n // it should only be called when the floating element is mounted on the DOM or visible on the screen.\n // it returns a \"cleanup\" function that should be invoked when the floating element is removed from the DOM or hidden from the screen.\n // see: https://floating-ui.com/docs/autoUpdate\n const cleanupFloatingUI = autoUpdate(\n _anchorElement,\n _floatingElement,\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n computeFloatingPosition\n );\n\n // this (teardown) function is run when the element is removed from the DOM\n return (): void => {\n cleanupFloatingUI();\n };\n }\n);\n"],"names":["HdsEnableCollisionDetectionOptions","DEFAULT_PLACEMENT","PLACEMENTS","ENABLE_COLLISION_DETECTION_OPTIONS","Object","values","DEFAULT_EDGE_DISTANCE","getFloatingUIOptions","options","placement","strategy","offsetOptions","flipOptions","padding","shiftOptions","limiter","limitShift","autoPlacementOptions","middlewareExtra","enableCollisionDetection","arrowElement","arrowPadding","matchToggleWidth","middleware","push","offset","flip","shift","autoPlacement","arrow","element","size","apply","rects","elements","requestAnimationFrame","assign","floating","style","width","reference","modifier","positional","named","_floatingElement","_anchorTarget","_anchorElement","document","querySelector","assert","HTMLElement","SVGElement","arrowSelector","selectedArrowElement","floatingOptions","computeFloatingPosition","state","computePosition","x","y","middlewareData","position","top","left","setAttribute","cleanupFloatingUI","autoUpdate"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hds-anchored-position.js","sources":["../../src/modifiers/hds-anchored-position.ts"],"sourcesContent":["/**\n * Copyright IBM Corp. 2021, 2025\n * SPDX-License-Identifier: MPL-2.0\n */\n\nimport { modifier } from 'ember-modifier';\nimport { assert } from '@ember/debug';\n\nimport {\n autoUpdate,\n computePosition,\n offset,\n flip,\n shift,\n limitShift,\n autoPlacement,\n arrow,\n // ---\n // this could be used in the future if we want to give consumers an option to hide the \"floating\" element when the \"anchor\" hides from the viewport\n // see: https://floating-ui.com/docs/hide\n // hide,\n // ---\n size,\n} from '@floating-ui/dom';\n\nimport type {\n Placement,\n Strategy,\n OffsetOptions,\n FlipOptions,\n ShiftOptions,\n AutoPlacementOptions,\n ArrowOptions,\n Middleware,\n Boundary,\n} from '@floating-ui/dom';\n\ntype BoundaryExtended = Boundary | (string & {});\n\nexport enum HdsEnableCollisionDetectionOptions {\n Shift = 'shift',\n Flip = 'flip',\n Auto = 'auto',\n}\n\nexport type HdsEnableCollisionDetection =\n `${HdsEnableCollisionDetectionOptions}`;\n\nexport const DEFAULT_PLACEMENT = 'bottom';\nexport const PLACEMENTS: Placement[] = [\n 'top',\n 'top-start',\n 'top-end',\n 'right',\n 'right-start',\n 'right-end',\n 'bottom',\n 'bottom-start',\n 'bottom-end',\n 'left',\n 'left-start',\n 'left-end',\n];\n\nexport const ENABLE_COLLISION_DETECTION_OPTIONS: HdsEnableCollisionDetection[] =\n Object.values(HdsEnableCollisionDetectionOptions);\n\n// share the same default value of \"padding\" for `flip/shift/autoPlacement` options\n// this refers to the minimum distance from the boundaries' edges (the viewport)\n// before the floating element changes its position (flips, shifts, or autoplace itself)\nconst DEFAULT_EDGE_DISTANCE = 8;\n\nexport type FloatingUIOptions = {\n placement?: Placement;\n strategy?: Strategy;\n offsetOptions?: OffsetOptions;\n flipOptions?: FlipOptions;\n shiftOptions?: ShiftOptions;\n autoPlacementOptions?: AutoPlacementOptions;\n middlewareExtra?: Middleware[];\n enableCollisionDetection?: boolean | HdsEnableCollisionDetection;\n arrowElement?: ArrowOptions['element'];\n arrowPadding?: ArrowOptions['padding'];\n matchToggleWidth?: boolean;\n boundary?: BoundaryExtended;\n};\n\nexport type HdsAnchoredPositionOptions = FloatingUIOptions & {\n arrowSelector?: string;\n};\n\n// resolve boundary selector/values to Floating UI Boundary\nconst resolveBoundary = (boundary?: BoundaryExtended): Boundary | undefined => {\n if (typeof boundary === 'string') {\n // this is necessary to satisfy TypeScript\n if (boundary === 'clippingAncestors') {\n return 'clippingAncestors';\n }\n const el = document.querySelector(boundary);\n assert(\n '`hds-anchored-position` modifier - the `boundary` selector `' +\n boundary +\n '` did not resolve to an element',\n el !== null && el.nodeType === Node.ELEMENT_NODE\n );\n return el;\n } else {\n return boundary;\n }\n};\n\n// we use this function to process all the options provided to the modifier in a single place,\n// in relation to the Floating UI APIs, and keep the modifier code more clean/simple\nexport const getFloatingUIOptions = (\n options: FloatingUIOptions\n): {\n placement: Placement;\n strategy: Strategy;\n middleware: Middleware[];\n} => {\n const {\n placement = DEFAULT_PLACEMENT,\n strategy = 'absolute', // we don't need to use `fixed` if we use the Popover API for the \"floating\" element (it puts the element in the `top-layer`)\n offsetOptions,\n flipOptions = { padding: DEFAULT_EDGE_DISTANCE },\n shiftOptions = { padding: DEFAULT_EDGE_DISTANCE, limiter: limitShift() },\n autoPlacementOptions = { padding: DEFAULT_EDGE_DISTANCE },\n middlewareExtra = [],\n enableCollisionDetection,\n arrowElement,\n arrowPadding,\n matchToggleWidth,\n boundary,\n } = options;\n\n const resolvedBoundary = resolveBoundary(boundary);\n\n // build options for each type of collision detection, adding the `boundary` if defined\n\n const flipOptsExtended: FlipOptions = {\n ...flipOptions,\n ...(resolvedBoundary ? { boundary: resolvedBoundary } : {}),\n };\n\n const autoPlacementOptsExtended: AutoPlacementOptions = {\n ...autoPlacementOptions,\n ...(resolvedBoundary ? { boundary: resolvedBoundary } : {}),\n };\n\n const shiftOptsExtended: ShiftOptions = {\n ...shiftOptions,\n ...(resolvedBoundary ? { boundary: resolvedBoundary } : {}),\n };\n\n // we build dynamically the list of middleware functions to invoke, depending on the options provided\n\n const middleware = [];\n\n // https://floating-ui.com/docs/offset\n middleware.push(offset(offsetOptions));\n\n // https://floating-ui.com/docs/flip\n // https://floating-ui.com/docs/shift\n // https://floating-ui.com/docs/autoPlacement\n if (\n enableCollisionDetection === true ||\n enableCollisionDetection === 'flip'\n ) {\n middleware.push(flip(flipOptsExtended));\n }\n if (\n enableCollisionDetection === true ||\n enableCollisionDetection === 'shift'\n ) {\n middleware.push(shift(shiftOptsExtended));\n }\n if (enableCollisionDetection === 'auto') {\n middleware.push(autoPlacement(autoPlacementOptsExtended));\n }\n\n // https://floating-ui.com/docs/arrow\n if (arrowElement) {\n middleware.push(\n arrow({\n element: arrowElement,\n padding: arrowPadding ?? 0,\n })\n );\n }\n\n // https://floating-ui.com/docs/size#match-reference-width\n if (matchToggleWidth) {\n middleware.push(\n size({\n apply({ rects, elements }) {\n // wrap Object.assign inside a requestAnimationFrame to avoid ResizeObserver loop limit exceeded error\n // https://github.com/floating-ui/floating-ui/issues/1740\n requestAnimationFrame(() => {\n Object.assign(elements.floating.style, {\n width: `${rects.reference.width}px`,\n });\n });\n },\n })\n );\n }\n\n middleware.push(...middlewareExtra);\n\n return {\n placement,\n strategy,\n middleware,\n };\n};\n\nexport interface HdsAnchoredPositionSignature {\n Element: HTMLElement;\n Args: {\n Positional: [HTMLElement | SVGElement];\n Named: HdsAnchoredPositionOptions;\n };\n}\n\n// Notice: we use a function-based modifier here instead of a class-based one\n// because it's quite simple in its logic, and doesn't require injecting services\n// see: https://github.com/ember-modifier/ember-modifier#function-based-modifiers\n\nexport default modifier<HdsAnchoredPositionSignature>(\n (element, positional, named = {}) => {\n // the element that \"floats\" next to the \"anchor\" (whose position is calculated in relation to the anchor)\n // notice: this is the element the Ember modifier is attached to\n const _floatingElement = element;\n\n // the element that acts as an \"anchor\" for the \"floating\" element\n // it can be a DOM (string) selector or a DOM element\n // notice: it's expressed as \"positional\" argument (array of arguments) for the modifier\n const _anchorTarget = positional[0];\n const _anchorElement =\n typeof _anchorTarget === 'string'\n ? document.querySelector(_anchorTarget)\n : _anchorTarget;\n\n assert(\n '`hds-anchored-position` modifier - the provided \"anchoring\" element is not defined correctly',\n _anchorElement instanceof HTMLElement ||\n _anchorElement instanceof SVGElement\n );\n\n // the \"arrow\" element (optional) associated with the \"floating\" element\n // it can be a DOM selector (string) or a DOM element\n // notice: it's declared inside the \"named\" argument (object) for the modifier\n // but we need to extract it also here so it can be used to assign inline styles to it\n let arrowElement: HTMLElement | SVGElement | undefined;\n\n if (named.arrowElement) {\n assert(\n '`hds-anchored-position` modifier - the `element` provided for the \"arrow\" element is not a valid DOM node',\n named.arrowElement instanceof HTMLElement ||\n named.arrowElement instanceof SVGElement\n );\n\n arrowElement = named.arrowElement;\n } else if (named.arrowSelector) {\n assert(\n '`hds-anchored-position` modifier - the `selector` provided for the \"arrow\" element must be a string',\n typeof named.arrowSelector === 'string'\n );\n\n const selectedArrowElement = document.querySelector(named.arrowSelector);\n if (selectedArrowElement instanceof HTMLElement) {\n arrowElement = selectedArrowElement;\n } else {\n assert(\n '`hds-anchored-position` modifier - the `selector` provided for the \"arrow\" element is not a valid DOM selector'\n );\n }\n }\n\n // the Floating UI \"options\" to apply to the \"floating\" element\n // notice: we spread the `named` argument and override its `arrowElement` value instead of setting it directly because Ember complains that modifier's arguments must be immutable\n const floatingOptions = getFloatingUIOptions({ ...named, arrowElement });\n\n const computeFloatingPosition = async () => {\n // important to know: `computePosition()` is not stateful, it only positions the \"floating\" element once\n // see: https://floating-ui.com/docs/computePosition\n const state = await computePosition(\n _anchorElement,\n _floatingElement,\n floatingOptions\n );\n\n const { x, y, placement, strategy, middlewareData } = state;\n\n Object.assign(_floatingElement.style, {\n position: strategy,\n top: `${y}px`,\n left: `${x}px`,\n // TODO? commenting this for now, will need to make this conditional to some argument (and understand how this relates to the `@height` argument)\n // maxHeight: `${middlewareData.size.availableHeight - 10}px`,\n });\n\n if (arrowElement && middlewareData.arrow) {\n // we assign a \"data\" attribute to the \"arrow\" element so we can use CSS (in the consuming components) to position/rotate it accordingly and we avoid calculating at runtime values that technically we already know\n // (similar to what Tippy.js does: https://github.com/atomiks/tippyjs/blob/master/src/scss/svg-arrow.scss)\n // IMPORTANT: floating-ui assumes the \"arrow\" container is square!\n arrowElement.setAttribute(\n 'data-hds-anchored-arrow-placement',\n placement\n );\n\n // we set `x` or `y` value (depends on the position of the arrow in relation to the \"floating\" element placement)\n // see: https://floating-ui.com/docs/arrow#usage\n Object.assign(arrowElement.style, {\n left:\n middlewareData.arrow.x != null ? `${middlewareData.arrow.x}px` : '',\n top:\n middlewareData.arrow.y != null ? `${middlewareData.arrow.y}px` : '',\n });\n }\n };\n\n // the `autoUpdate` function automatically updates the position of the floating element when necessary.\n // it should only be called when the floating element is mounted on the DOM or visible on the screen.\n // it returns a \"cleanup\" function that should be invoked when the floating element is removed from the DOM or hidden from the screen.\n // see: https://floating-ui.com/docs/autoUpdate\n const cleanupFloatingUI = autoUpdate(\n _anchorElement,\n _floatingElement,\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n computeFloatingPosition\n );\n\n // this (teardown) function is run when the element is removed from the DOM\n return (): void => {\n cleanupFloatingUI();\n };\n }\n);\n"],"names":["HdsEnableCollisionDetectionOptions","DEFAULT_PLACEMENT","PLACEMENTS","ENABLE_COLLISION_DETECTION_OPTIONS","Object","values","DEFAULT_EDGE_DISTANCE","resolveBoundary","boundary","el","document","querySelector","assert","nodeType","Node","ELEMENT_NODE","getFloatingUIOptions","options","placement","strategy","offsetOptions","flipOptions","padding","shiftOptions","limiter","limitShift","autoPlacementOptions","middlewareExtra","enableCollisionDetection","arrowElement","arrowPadding","matchToggleWidth","resolvedBoundary","flipOptsExtended","autoPlacementOptsExtended","shiftOptsExtended","middleware","push","offset","flip","shift","autoPlacement","arrow","element","size","apply","rects","elements","requestAnimationFrame","assign","floating","style","width","reference","modifier","positional","named","_floatingElement","_anchorTarget","_anchorElement","HTMLElement","SVGElement","arrowSelector","selectedArrowElement","floatingOptions","computeFloatingPosition","state","computePosition","x","y","middlewareData","position","top","left","setAttribute","cleanupFloatingUI","autoUpdate"],"mappings":"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"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import Service from '@ember/service';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { g, i } from 'decorator-transforms/runtime';
|
|
4
|
+
|
|
5
|
+
let HdsThemeValues = /*#__PURE__*/function (HdsThemeValues) {
|
|
6
|
+
// default (original HDS)
|
|
7
|
+
HdsThemeValues["Default"] = "default";
|
|
8
|
+
// system settings (prefers-color-scheme)
|
|
9
|
+
HdsThemeValues["System"] = "system";
|
|
10
|
+
// user settings for dark/light
|
|
11
|
+
HdsThemeValues["Light"] = "light";
|
|
12
|
+
HdsThemeValues["Dark"] = "dark";
|
|
13
|
+
return HdsThemeValues;
|
|
14
|
+
}({});
|
|
15
|
+
let HdsModesBaseValues = /*#__PURE__*/function (HdsModesBaseValues) {
|
|
16
|
+
HdsModesBaseValues["Default"] = "default";
|
|
17
|
+
return HdsModesBaseValues;
|
|
18
|
+
}({});
|
|
19
|
+
let HdsModesLightValues = /*#__PURE__*/function (HdsModesLightValues) {
|
|
20
|
+
HdsModesLightValues["CdsG0"] = "cds-g0";
|
|
21
|
+
HdsModesLightValues["CdsG10"] = "cds-g10";
|
|
22
|
+
return HdsModesLightValues;
|
|
23
|
+
}({});
|
|
24
|
+
let HdsModesDarkValues = /*#__PURE__*/function (HdsModesDarkValues) {
|
|
25
|
+
HdsModesDarkValues["CdsG90"] = "cds-g90";
|
|
26
|
+
HdsModesDarkValues["CdsG100"] = "cds-g100";
|
|
27
|
+
return HdsModesDarkValues;
|
|
28
|
+
}({});
|
|
29
|
+
const THEMES = Object.values(HdsThemeValues);
|
|
30
|
+
const MODES_LIGHT = Object.values(HdsModesLightValues);
|
|
31
|
+
const MODES_DARK = Object.values(HdsModesDarkValues);
|
|
32
|
+
const MODES = [...Object.values(HdsModesBaseValues), ...MODES_LIGHT, ...MODES_DARK];
|
|
33
|
+
const HDS_THEMING_LOCALSTORAGE_DATA = 'hds-theming-data';
|
|
34
|
+
const DEFAULT_THEMING_OPTION_LIGHT_THEME = HdsModesLightValues.CdsG0;
|
|
35
|
+
const DEFAULT_THEMING_OPTION_DARK_THEME = HdsModesDarkValues.CdsG100;
|
|
36
|
+
// We use this guard function to check if the data parsed from `localStorage` conforms to the `StoredThemingData` type and so is safe to use.
|
|
37
|
+
// This prevents the application from using corrupted, malformed or malicious data, by validating the object structure, theme, and mode values.
|
|
38
|
+
|
|
39
|
+
function isSafeStoredThemingData(data) {
|
|
40
|
+
if (typeof data !== 'object' || data === null) return false;
|
|
41
|
+
const d = data;
|
|
42
|
+
const isSafeThemeData =
|
|
43
|
+
// there is no stored `theme` key in the object (eg. the `default` theme was selected)
|
|
44
|
+
!('theme' in d) ||
|
|
45
|
+
// there is a `theme` value and is one of the valid `HdsThemes`
|
|
46
|
+
d['theme'] === undefined || THEMES.includes(d['theme']);
|
|
47
|
+
const options = d['options'];
|
|
48
|
+
const isSafeOptionsData =
|
|
49
|
+
// there is no stored `options` key in the object (eg. it's the first run of the application)
|
|
50
|
+
!('options' in d) ||
|
|
51
|
+
// there is an `options` value and has valid entries
|
|
52
|
+
typeof options === 'object' && options !== null && 'lightTheme' in options && MODES_LIGHT.includes(options['lightTheme']) && 'darkTheme' in options && MODES_DARK.includes(options['darkTheme']);
|
|
53
|
+
return isSafeThemeData && isSafeOptionsData;
|
|
54
|
+
}
|
|
55
|
+
class HdsThemingService extends Service {
|
|
56
|
+
static {
|
|
57
|
+
g(this.prototype, "_currentTheme", [tracked], function () {
|
|
58
|
+
return undefined;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
#_currentTheme = (i(this, "_currentTheme"), void 0);
|
|
62
|
+
static {
|
|
63
|
+
g(this.prototype, "_currentMode", [tracked], function () {
|
|
64
|
+
return undefined;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
#_currentMode = (i(this, "_currentMode"), void 0);
|
|
68
|
+
static {
|
|
69
|
+
g(this.prototype, "_currentLightTheme", [tracked], function () {
|
|
70
|
+
return DEFAULT_THEMING_OPTION_LIGHT_THEME;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
#_currentLightTheme = (i(this, "_currentLightTheme"), void 0);
|
|
74
|
+
static {
|
|
75
|
+
g(this.prototype, "_currentDarkTheme", [tracked], function () {
|
|
76
|
+
return DEFAULT_THEMING_OPTION_DARK_THEME;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
#_currentDarkTheme = (i(this, "_currentDarkTheme"), void 0);
|
|
80
|
+
static {
|
|
81
|
+
g(this.prototype, "globalOnSetTheme", [tracked]);
|
|
82
|
+
}
|
|
83
|
+
#globalOnSetTheme = (i(this, "globalOnSetTheme"), void 0);
|
|
84
|
+
initializeTheme() {
|
|
85
|
+
const rawStoredThemingData = localStorage.getItem(HDS_THEMING_LOCALSTORAGE_DATA);
|
|
86
|
+
if (rawStoredThemingData !== null) {
|
|
87
|
+
let storedThemingData;
|
|
88
|
+
try {
|
|
89
|
+
storedThemingData = JSON.parse(rawStoredThemingData);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
// malformed JSON in localStorage, ignore and proceed with defaults
|
|
92
|
+
console.error(`Error while reading local storage '${HDS_THEMING_LOCALSTORAGE_DATA}' for theming`, error);
|
|
93
|
+
}
|
|
94
|
+
if (isSafeStoredThemingData(storedThemingData)) {
|
|
95
|
+
this.setTheme({
|
|
96
|
+
theme: storedThemingData.theme,
|
|
97
|
+
options: storedThemingData.options
|
|
98
|
+
});
|
|
99
|
+
} else {
|
|
100
|
+
// if data is not safe or malformed, reset theming to its defaults
|
|
101
|
+
this.setTheme({
|
|
102
|
+
theme: undefined,
|
|
103
|
+
options: undefined
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
setTheme({
|
|
109
|
+
theme,
|
|
110
|
+
options,
|
|
111
|
+
onSetTheme
|
|
112
|
+
}) {
|
|
113
|
+
if (options !== undefined) {
|
|
114
|
+
// if we have new options, we override the current ones (`lightTheme` / `darkTheme`)
|
|
115
|
+
// these options can be used by consumers that want to customize how they apply theming
|
|
116
|
+
// (and used by the showcase for the custom theming / theme switching logic)
|
|
117
|
+
if (Object.hasOwn(options, 'lightTheme') && Object.hasOwn(options, 'darkTheme')) {
|
|
118
|
+
const {
|
|
119
|
+
lightTheme,
|
|
120
|
+
darkTheme
|
|
121
|
+
} = options;
|
|
122
|
+
this._currentLightTheme = lightTheme;
|
|
123
|
+
this._currentDarkTheme = darkTheme;
|
|
124
|
+
} else {
|
|
125
|
+
// fallback if something goes wrong
|
|
126
|
+
this._currentLightTheme = DEFAULT_THEMING_OPTION_LIGHT_THEME;
|
|
127
|
+
this._currentDarkTheme = DEFAULT_THEMING_OPTION_DARK_THEME;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// set the current theme/mode (`currentTheme` / `currentMode`)
|
|
132
|
+
if (theme === undefined ||
|
|
133
|
+
// standard (no theming)
|
|
134
|
+
!THEMES.includes(theme) // handle possible errors
|
|
135
|
+
) {
|
|
136
|
+
this._currentTheme = undefined;
|
|
137
|
+
this._currentMode = undefined;
|
|
138
|
+
} else if (theme === HdsThemeValues.Default // default (original HDS)
|
|
139
|
+
) {
|
|
140
|
+
this._currentTheme = HdsThemeValues.Default;
|
|
141
|
+
this._currentMode = undefined;
|
|
142
|
+
} else if (theme === HdsThemeValues.System // system (prefers-color-scheme)
|
|
143
|
+
) {
|
|
144
|
+
this._currentTheme = HdsThemeValues.System;
|
|
145
|
+
this._currentMode = undefined;
|
|
146
|
+
} else {
|
|
147
|
+
this._currentTheme = theme;
|
|
148
|
+
if (this._currentTheme === HdsThemeValues.Light) {
|
|
149
|
+
this._currentMode = this._currentLightTheme;
|
|
150
|
+
}
|
|
151
|
+
if (this._currentTheme === HdsThemeValues.Dark) {
|
|
152
|
+
this._currentMode = this._currentDarkTheme;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// IMPORTANT: for this to work, it needs to be the `<html>` tag (it's the `:root` in CSS)
|
|
157
|
+
const rootElement = document.querySelector('html');
|
|
158
|
+
if (!rootElement) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// remove or update the CSS selectors applied to the root element (depending on the `theme`/`mode` arguments)
|
|
162
|
+
const hdsThemingClassesToRemove = Array.from(rootElement.classList).filter(className => className.match(/^hds-(theme|mode)/));
|
|
163
|
+
rootElement.classList.remove(...hdsThemingClassesToRemove);
|
|
164
|
+
if (this._currentTheme !== undefined) {
|
|
165
|
+
rootElement.classList.add(`hds-theme-${this._currentTheme}`);
|
|
166
|
+
}
|
|
167
|
+
if (this._currentMode !== undefined) {
|
|
168
|
+
rootElement.classList.add(`hds-mode-${this._currentMode}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// store the current theme and theming options in local storage
|
|
172
|
+
localStorage.setItem(HDS_THEMING_LOCALSTORAGE_DATA, JSON.stringify({
|
|
173
|
+
theme: this._currentTheme,
|
|
174
|
+
options: {
|
|
175
|
+
lightTheme: this._currentLightTheme,
|
|
176
|
+
darkTheme: this._currentDarkTheme
|
|
177
|
+
}
|
|
178
|
+
}));
|
|
179
|
+
|
|
180
|
+
// this is a general callback that can be defined globally (by extending the service)
|
|
181
|
+
if (this.globalOnSetTheme) {
|
|
182
|
+
this.globalOnSetTheme({
|
|
183
|
+
currentTheme: this._currentTheme,
|
|
184
|
+
currentMode: this._currentMode
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// this is a "local" callback that can be defined "locally" (eg. in a theme switcher)
|
|
189
|
+
if (onSetTheme) {
|
|
190
|
+
onSetTheme({
|
|
191
|
+
currentTheme: this._currentTheme,
|
|
192
|
+
currentMode: this._currentMode
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// getters used for reactivity in the components/services using this service
|
|
198
|
+
|
|
199
|
+
get currentTheme() {
|
|
200
|
+
return this._currentTheme;
|
|
201
|
+
}
|
|
202
|
+
get currentMode() {
|
|
203
|
+
return this._currentMode;
|
|
204
|
+
}
|
|
205
|
+
get currentLightTheme() {
|
|
206
|
+
return this._currentLightTheme;
|
|
207
|
+
}
|
|
208
|
+
get currentDarkTheme() {
|
|
209
|
+
return this._currentDarkTheme;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export { DEFAULT_THEMING_OPTION_DARK_THEME, DEFAULT_THEMING_OPTION_LIGHT_THEME, HDS_THEMING_LOCALSTORAGE_DATA, HdsModesBaseValues, HdsModesDarkValues, HdsModesLightValues, HdsThemeValues, MODES, MODES_DARK, MODES_LIGHT, THEMES, HdsThemingService as default };
|
|
214
|
+
//# sourceMappingURL=hds-theming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hds-theming.js","sources":["../../src/services/hds-theming.ts"],"sourcesContent":["import Service from '@ember/service';\nimport { tracked } from '@glimmer/tracking';\n\nexport enum HdsThemeValues {\n // default (original HDS)\n Default = 'default',\n // system settings (prefers-color-scheme)\n System = 'system',\n // user settings for dark/light\n Light = 'light',\n Dark = 'dark',\n}\n\nexport enum HdsModesBaseValues {\n Default = 'default',\n}\n\nexport enum HdsModesLightValues {\n CdsG0 = 'cds-g0',\n CdsG10 = 'cds-g10',\n}\n\nexport enum HdsModesDarkValues {\n CdsG90 = 'cds-g90',\n CdsG100 = 'cds-g100',\n}\n\nexport type HdsThemes = `${HdsThemeValues}`;\nexport type HdsModes =\n | `${HdsModesBaseValues}`\n | `${HdsModesLightValues}`\n | `${HdsModesDarkValues}`;\nexport type HdsModesLight = `${HdsModesLightValues}`;\nexport type HdsModesDark = `${HdsModesDarkValues}`;\n\ntype HdsThemingOptions = {\n lightTheme: HdsModesLight;\n darkTheme: HdsModesDark;\n};\n\ntype SetThemeArgs = {\n theme: HdsThemes | undefined;\n options?: HdsThemingOptions;\n onSetTheme?: HdsOnSetThemeCallback;\n};\n\nexport type HdsOnSetThemeCallbackArgs = {\n currentTheme: HdsThemes | undefined;\n currentMode: HdsModes | undefined;\n};\n\nexport type HdsOnSetThemeCallback = (args: HdsOnSetThemeCallbackArgs) => void;\n\nexport const THEMES: HdsThemes[] = Object.values(HdsThemeValues);\nexport const MODES_LIGHT: HdsModesLight[] = Object.values(HdsModesLightValues);\nexport const MODES_DARK: HdsModesDark[] = Object.values(HdsModesDarkValues);\nexport const MODES: HdsModes[] = [\n ...Object.values(HdsModesBaseValues),\n ...MODES_LIGHT,\n ...MODES_DARK,\n];\n\nexport const HDS_THEMING_LOCALSTORAGE_DATA = 'hds-theming-data';\n\nexport const DEFAULT_THEMING_OPTION_LIGHT_THEME = HdsModesLightValues.CdsG0;\nexport const DEFAULT_THEMING_OPTION_DARK_THEME = HdsModesDarkValues.CdsG100;\n\ntype StoredThemingData = {\n theme: HdsThemes | undefined;\n options: HdsThemingOptions;\n};\n\n// We use this guard function to check if the data parsed from `localStorage` conforms to the `StoredThemingData` type and so is safe to use.\n// This prevents the application from using corrupted, malformed or malicious data, by validating the object structure, theme, and mode values.\n\nfunction isSafeStoredThemingData(data: unknown): data is StoredThemingData {\n if (typeof data !== 'object' || data === null) return false;\n\n const d = data as Record<string, unknown>;\n\n const isSafeThemeData =\n // there is no stored `theme` key in the object (eg. the `default` theme was selected)\n !('theme' in d) ||\n // there is a `theme` value and is one of the valid `HdsThemes`\n d['theme'] === undefined ||\n THEMES.includes(d['theme'] as HdsThemes);\n\n const options = d['options'] as Record<string, unknown> | undefined;\n\n const isSafeOptionsData =\n // there is no stored `options` key in the object (eg. it's the first run of the application)\n !('options' in d) ||\n // there is an `options` value and has valid entries\n (typeof options === 'object' &&\n options !== null &&\n 'lightTheme' in options &&\n MODES_LIGHT.includes(options['lightTheme'] as HdsModesLight) &&\n 'darkTheme' in options &&\n MODES_DARK.includes(options['darkTheme'] as HdsModesDark));\n\n return isSafeThemeData && isSafeOptionsData;\n}\n\nexport default class HdsThemingService extends Service {\n @tracked _currentTheme: HdsThemes | undefined = undefined;\n @tracked _currentMode: HdsModes | undefined = undefined;\n @tracked _currentLightTheme: HdsModesLight =\n DEFAULT_THEMING_OPTION_LIGHT_THEME;\n @tracked _currentDarkTheme: HdsModesDark = DEFAULT_THEMING_OPTION_DARK_THEME;\n @tracked globalOnSetTheme: HdsOnSetThemeCallback | undefined;\n\n initializeTheme() {\n const rawStoredThemingData = localStorage.getItem(\n HDS_THEMING_LOCALSTORAGE_DATA\n );\n\n if (rawStoredThemingData !== null) {\n let storedThemingData: unknown;\n try {\n storedThemingData = JSON.parse(rawStoredThemingData);\n } catch (error) {\n // malformed JSON in localStorage, ignore and proceed with defaults\n console.error(\n `Error while reading local storage '${HDS_THEMING_LOCALSTORAGE_DATA}' for theming`,\n error\n );\n }\n\n if (isSafeStoredThemingData(storedThemingData)) {\n this.setTheme({\n theme: storedThemingData.theme,\n options: storedThemingData.options,\n });\n } else {\n // if data is not safe or malformed, reset theming to its defaults\n this.setTheme({\n theme: undefined,\n options: undefined,\n });\n }\n }\n }\n\n setTheme({ theme, options, onSetTheme }: SetThemeArgs) {\n if (options !== undefined) {\n // if we have new options, we override the current ones (`lightTheme` / `darkTheme`)\n // these options can be used by consumers that want to customize how they apply theming\n // (and used by the showcase for the custom theming / theme switching logic)\n if (\n Object.hasOwn(options, 'lightTheme') &&\n Object.hasOwn(options, 'darkTheme')\n ) {\n const { lightTheme, darkTheme } = options;\n\n this._currentLightTheme = lightTheme;\n this._currentDarkTheme = darkTheme;\n } else {\n // fallback if something goes wrong\n this._currentLightTheme = DEFAULT_THEMING_OPTION_LIGHT_THEME;\n this._currentDarkTheme = DEFAULT_THEMING_OPTION_DARK_THEME;\n }\n }\n\n // set the current theme/mode (`currentTheme` / `currentMode`)\n if (\n theme === undefined || // standard (no theming)\n !THEMES.includes(theme) // handle possible errors\n ) {\n this._currentTheme = undefined;\n this._currentMode = undefined;\n } else if (\n theme === HdsThemeValues.Default // default (original HDS)\n ) {\n this._currentTheme = HdsThemeValues.Default;\n this._currentMode = undefined;\n } else if (\n theme === HdsThemeValues.System // system (prefers-color-scheme)\n ) {\n this._currentTheme = HdsThemeValues.System;\n this._currentMode = undefined;\n } else {\n this._currentTheme = theme;\n if (this._currentTheme === HdsThemeValues.Light) {\n this._currentMode = this._currentLightTheme;\n }\n if (this._currentTheme === HdsThemeValues.Dark) {\n this._currentMode = this._currentDarkTheme;\n }\n }\n\n // IMPORTANT: for this to work, it needs to be the `<html>` tag (it's the `:root` in CSS)\n const rootElement = document.querySelector('html');\n\n if (!rootElement) {\n return;\n }\n // remove or update the CSS selectors applied to the root element (depending on the `theme`/`mode` arguments)\n const hdsThemingClassesToRemove = Array.from(rootElement.classList).filter(\n (className) => className.match(/^hds-(theme|mode)/)\n );\n rootElement.classList.remove(...hdsThemingClassesToRemove);\n if (this._currentTheme !== undefined) {\n rootElement.classList.add(`hds-theme-${this._currentTheme}`);\n }\n if (this._currentMode !== undefined) {\n rootElement.classList.add(`hds-mode-${this._currentMode}`);\n }\n\n // store the current theme and theming options in local storage\n localStorage.setItem(\n HDS_THEMING_LOCALSTORAGE_DATA,\n JSON.stringify({\n theme: this._currentTheme,\n options: {\n lightTheme: this._currentLightTheme,\n darkTheme: this._currentDarkTheme,\n },\n })\n );\n\n // this is a general callback that can be defined globally (by extending the service)\n if (this.globalOnSetTheme) {\n this.globalOnSetTheme({\n currentTheme: this._currentTheme,\n currentMode: this._currentMode,\n });\n }\n\n // this is a \"local\" callback that can be defined \"locally\" (eg. in a theme switcher)\n if (onSetTheme) {\n onSetTheme({\n currentTheme: this._currentTheme,\n currentMode: this._currentMode,\n });\n }\n }\n\n // getters used for reactivity in the components/services using this service\n\n get currentTheme(): HdsThemes | undefined {\n return this._currentTheme;\n }\n\n get currentMode(): HdsModes | undefined {\n return this._currentMode;\n }\n\n get currentLightTheme(): HdsModesLight {\n return this._currentLightTheme;\n }\n\n get currentDarkTheme(): HdsModesDark {\n return this._currentDarkTheme;\n }\n}\n"],"names":["HdsThemeValues","HdsModesBaseValues","HdsModesLightValues","HdsModesDarkValues","THEMES","Object","values","MODES_LIGHT","MODES_DARK","MODES","HDS_THEMING_LOCALSTORAGE_DATA","DEFAULT_THEMING_OPTION_LIGHT_THEME","CdsG0","DEFAULT_THEMING_OPTION_DARK_THEME","CdsG100","isSafeStoredThemingData","data","d","isSafeThemeData","undefined","includes","options","isSafeOptionsData","HdsThemingService","Service","g","prototype","tracked","i","void 0","initializeTheme","rawStoredThemingData","localStorage","getItem","storedThemingData","JSON","parse","error","console","setTheme","theme","onSetTheme","hasOwn","lightTheme","darkTheme","_currentLightTheme","_currentDarkTheme","_currentTheme","_currentMode","Default","System","Light","Dark","rootElement","document","querySelector","hdsThemingClassesToRemove","Array","from","classList","filter","className","match","remove","add","setItem","stringify","globalOnSetTheme","currentTheme","currentMode","currentLightTheme","currentDarkTheme"],"mappings":"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"}
|
package/dist/services.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
export { DEFAULT_THEMING_OPTION_DARK_THEME, DEFAULT_THEMING_OPTION_LIGHT_THEME, HDS_THEMING_LOCALSTORAGE_DATA, HdsModesBaseValues, HdsModesDarkValues, HdsModesLightValues, HdsThemeValues, MODES, MODES_DARK, MODES_LIGHT, THEMES } from './services/hds-theming.js';
|
|
2
2
|
//# sourceMappingURL=services.js.map
|