@santi020k/lumen-react 4.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createElement } from 'react';
3
- import { composeClassName } from '@santi020k/lumen-core';
3
+ import { composeClassName, normalizeLumenProgress, resolveLumenLoadingSemantics, resolveLumenSkeletonAnimation, resolveLumenSkeletonShape, resolveLumenSkeletonSize } from '@santi020k/lumen-core';
4
4
  const Primitive = ({ as, className, uiClassName, ...props }) => {
5
5
  const tag = as ?? 'div';
6
6
  const safeClassName = typeof className === 'string' ? className : undefined;
@@ -42,16 +42,24 @@ export const Grid = ({ as = 'div', className, columns = 'auto', gap = 'group', m
42
42
  export const Input = ({ className, ref, type = 'text', visualSize = 'default', ...props }) => (_jsx("input", { className: composeClassName('ui-input', visualSize === 'sm' && 'ui-input--sm', visualSize === 'lg' && 'ui-input--lg', className), ref: ref, type: type, ...props }));
43
43
  export const Label = ({ className, ...props }) => (_jsx("label", { className: composeClassName('ui-label', className), ...props }));
44
44
  export const Progress = ({ className, max = 100, value = 0, ...props }) => {
45
- const safeMax = max > 0 ? max : 100;
46
- const safeValue = Math.min(safeMax, Math.max(0, value));
47
- const percentage = (safeValue / safeMax) * 100;
45
+ const { max: safeMax, percentage, value: safeValue } = normalizeLumenProgress(max, value);
48
46
  return (_jsx("div", { "aria-valuemax": safeMax, "aria-valuemin": 0, "aria-valuenow": safeValue, className: composeClassName('ui-progress', className), role: "progressbar", ...props, children: _jsx("span", { className: "ui-progress__bar", "data-slot": "progress-indicator", style: { width: `${percentage}%` } }) }));
49
47
  };
50
48
  export const Separator = ({ className, orientation = 'horizontal', ...props }) => (_jsx("hr", { "aria-orientation": orientation, className: composeClassName('ui-separator', `ui-separator--${orientation}`, className), "data-orientation": orientation, ...props }));
51
- export const Skeleton = ({ className, ...props }) => (_jsx("div", { className: composeClassName('ui-skeleton', className), ...props }));
49
+ export const Skeleton = ({ animation, 'aria-hidden': ariaHidden, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, className, height, role, shape, style, width, ...props }) => {
50
+ const semantics = resolveLumenLoadingSemantics({ ariaHidden, ariaLabel, ariaLabelledby, role });
51
+ const resolvedShape = resolveLumenSkeletonShape(shape);
52
+ const resolvedAnimation = resolveLumenSkeletonAnimation(animation);
53
+ const skeletonStyle = {
54
+ '--ui-skeleton-height': resolveLumenSkeletonSize(height),
55
+ '--ui-skeleton-width': resolveLumenSkeletonSize(width),
56
+ ...style
57
+ };
58
+ return (_jsx("div", { "aria-hidden": ariaHidden ?? (semantics.ariaHidden ? true : undefined), "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, className: composeClassName('ui-skeleton', resolvedShape !== 'rectangle' && `ui-skeleton--${resolvedShape}`, resolvedAnimation === 'pulse' && 'ui-skeleton--pulse', resolvedAnimation === 'none' && 'ui-skeleton--static', className), role: role ?? semantics.role, style: skeletonStyle, ...props }));
59
+ };
52
60
  export const Spinner = ({ 'aria-hidden': ariaHidden, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, className, role, ...props }) => {
53
- const isAccessible = Boolean(ariaLabel || ariaLabelledby);
54
- return (_jsx("span", { "aria-hidden": ariaHidden ?? (isAccessible ? undefined : true), "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, className: composeClassName('ui-spinner', className), role: role ?? (isAccessible ? 'status' : undefined), ...props }));
61
+ const semantics = resolveLumenLoadingSemantics({ ariaHidden, ariaLabel, ariaLabelledby, role });
62
+ return (_jsx("span", { "aria-hidden": ariaHidden ?? (semantics.ariaHidden ? true : undefined), "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, className: composeClassName('ui-spinner', className), role: role ?? semantics.role, ...props }));
55
63
  };
56
64
  export const Stack = ({ align = 'stretch', as = 'div', className, direction = 'vertical', gap = 'group', justify = 'start', wrap = false, ...props }) => createElement(as, {
57
65
  className: composeClassName('ui-stack', `ui-stack--${direction}`, `ui-stack--gap-${gap}`, `ui-stack--align-${align}`, `ui-stack--justify-${justify}`, wrap && 'ui-stack--wrap', className),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@santi020k/lumen-react",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -123,8 +123,8 @@
123
123
  "lumen": "./bin/lumen.mjs"
124
124
  },
125
125
  "dependencies": {
126
- "@santi020k/lumen": "^4.0.0",
127
- "@santi020k/lumen-core": "^4.0.0",
126
+ "@santi020k/lumen": "^4.1.0",
127
+ "@santi020k/lumen-core": "^4.1.0",
128
128
  "@tanstack/react-table": "9.2.4",
129
129
  "uqr": "^0.1.3"
130
130
  },
@@ -172,6 +172,17 @@
172
172
  }
173
173
  }
174
174
 
175
+ @keyframes ui-skeleton-pulse {
176
+ 0%,
177
+ 100% {
178
+ opacity: 1;
179
+ }
180
+
181
+ 50% {
182
+ opacity: 0.55;
183
+ }
184
+ }
185
+
175
186
  @keyframes ui-spin {
176
187
  to {
177
188
  transform: rotate(360deg);
@@ -790,15 +801,21 @@
790
801
  background-image:
791
802
  linear-gradient(45deg, transparent 50%, hsl(var(--ink-muted)) 50%),
792
803
  linear-gradient(135deg, hsl(var(--ink-muted)) 50%, transparent 50%);
793
- background-position:
794
- calc(100% - 1rem) 50%,
795
- calc(100% - 0.72rem) 50%;
804
+ background-position: var(--_ui-select-chevron, calc(100% - 1rem) 50%, calc(100% - 0.72rem) 50%);
796
805
  background-size:
797
806
  0.32rem 0.32rem,
798
807
  0.32rem 0.32rem;
799
808
  background-repeat: no-repeat;
800
809
  }
801
810
 
811
+ [dir="rtl"] {
812
+ --_ui-select-chevron: 0.72rem 50%, 1rem 50%;
813
+ }
814
+
815
+ [dir="ltr"] {
816
+ --_ui-select-chevron: calc(100% - 1rem) 50%, calc(100% - 0.72rem) 50%;
817
+ }
818
+
802
819
  .ui-label {
803
820
  color: hsl(var(--ink));
804
821
  font-size: 0.875rem;
@@ -1007,7 +1024,9 @@
1007
1024
  }
1008
1025
 
1009
1026
  .ui-skeleton {
1010
- min-height: 1rem;
1027
+ /* A default height, not a minimum, lets explicit styles and classes size placeholders below 1rem. */
1028
+ width: var(--ui-skeleton-width, auto);
1029
+ height: var(--ui-skeleton-height, 1rem);
1011
1030
  border-radius: var(--ui-radius-sm);
1012
1031
  background: linear-gradient(
1013
1032
  90deg,
@@ -1019,6 +1038,42 @@
1019
1038
  animation: ui-shimmer 2.2s linear infinite;
1020
1039
  }
1021
1040
 
1041
+ .ui-skeleton:where(:not(:empty)) {
1042
+ height: var(--ui-skeleton-height, auto);
1043
+ min-height: 1rem;
1044
+ }
1045
+
1046
+ lumen-skeleton.ui-skeleton,
1047
+ lumen-progress.ui-progress {
1048
+ display: block;
1049
+ }
1050
+
1051
+ .ui-skeleton--text {
1052
+ height: var(--ui-skeleton-height, 0.75rem);
1053
+ }
1054
+
1055
+ .ui-skeleton--circle {
1056
+ flex: 0 0 auto;
1057
+ width: var(--ui-skeleton-width, var(--ui-skeleton-height, 2.5rem));
1058
+ height: var(--ui-skeleton-height, var(--ui-skeleton-width, 2.5rem));
1059
+ border-radius: 50%;
1060
+ }
1061
+
1062
+ .ui-skeleton--pulse {
1063
+ background: hsl(var(--surface-strong));
1064
+ animation: ui-skeleton-pulse 1.6s ease-in-out infinite;
1065
+ }
1066
+
1067
+ .ui-skeleton--static {
1068
+ animation: none;
1069
+ }
1070
+
1071
+ @media (prefers-reduced-motion: reduce) {
1072
+ .ui-skeleton {
1073
+ animation: none;
1074
+ }
1075
+ }
1076
+
1022
1077
  .ui-spinner {
1023
1078
  box-sizing: border-box;
1024
1079
  display: inline-block;
@@ -1586,7 +1641,9 @@ lumen-dialog.ui-dialog:not([hidden]):has(> [data-slot="dialog-body"]) {
1586
1641
 
1587
1642
  .ui-input-otp__native[data-ui-enhanced="true"] {
1588
1643
  position: absolute;
1589
- width: 1px;
1644
+ inset-block-start: 0;
1645
+ inset-inline-start: 0;
1646
+ width: 100%;
1590
1647
  height: 1px;
1591
1648
  overflow: hidden;
1592
1649
  clip-path: inset(50%);