@mario_hahn/jumpy-ui 0.7.0 → 0.8.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/README.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # @mario_hahn/jumpy-ui
2
2
 
3
+ ## Sticky tables and selection
4
+
5
+ `JumpTable stickyHeader` fixes both the header and footer inside the scrollable
6
+ container. They use `--jumpy-cmp-table-backdrop-color` for a continuous background
7
+ behind the decorative cell surfaces. The default resolves to the opaque semantic
8
+ floating surface in each preset. Keep any custom backdrop override opaque.
9
+
10
+ `JumpTableCell` and `JumpTableHeaderCell` support `pinned="left"` or `pinned="right"`;
11
+ use `pinnedEdge` for the edge divider. Pinned cells use the same backdrop as the
12
+ sticky bands. Set the container's maximum height through `containerProps.style`.
13
+
14
+ Selection preserves normal text weight for table cells and list-item labels.
15
+ For deliberate emphasis, use `innerClasses.text.style.fontWeight` on a table cell
16
+ or `innerClasses.label.style.fontWeight` on a list item. Headers stay emphasized;
17
+ selection surfaces and accessibility attributes are independent of typography.
18
+
19
+ ## Button sizes
20
+
21
+ ```tsx
22
+ import { JumpButton, JumpySize } from '@mario_hahn/jumpy-ui'
23
+
24
+ <JumpButton>Standard</JumpButton>
25
+ <JumpButton size={JumpySize.medium}>Compact</JumpButton>
26
+ <JumpButton size={JumpySize.largeXL}>Large</JumpButton>
27
+ ```
28
+
29
+ `size` accepts a Jumpy sizing token, not a pixel number. The standard theme resolves
30
+ `medium` to 32px and `largeXL` to 48px. Omitting the prop preserves the existing
31
+ button layout (normally 40px). Explicit sizes adjust vertical padding; compact
32
+ buttons also use smaller typography, icons and horizontal padding. The token sets
33
+ a minimum height: content is never clipped when a very small token or larger
34
+ custom typography is used. Consumer `style` overrides retain precedence.
35
+
3
36
  ## Theme overrides
4
37
 
5
38
  Use semantic colors for brand-wide changes and action overrides for individual
@@ -42,7 +75,7 @@ Jumpy Components als ein gemeinsames UI-Paket.
42
75
  Starting with 0.5.0, Jumpy UI uses the public npmjs registry. No package token is required to install:
43
76
 
44
77
  ```bash
45
- npm install @mario_hahn/jumpy-ui@^0.7.0
78
+ npm install @mario_hahn/jumpy-ui@^0.8.0
46
79
  ```
47
80
 
48
81
  The public npm package uses the `@mario_hahn` scope. Older GitHub Packages releases
@@ -23765,13 +23765,33 @@ var providerStyles = `
23765
23765
  [data-jumpy-theme='true'] [data-jumpy-slot='table-container'][data-sticky-header='true'] thead,
23766
23766
  [data-jumpy-theme='true'] [data-jumpy-slot='table-container'][data-sticky-header='true'] tfoot {
23767
23767
  position: sticky;
23768
- z-index: 10;
23768
+ /* Above pinned body cells (z-index 10), with a full-width opaque surface. */
23769
+ z-index: 20;
23770
+ /* The inset decorative cell surfaces are not an occluding backdrop. */
23771
+ background-color: var(--jumpy-cmp-table-backdrop-color);
23769
23772
  }
23770
23773
 
23771
23774
  [data-jumpy-theme='true'] [data-jumpy-slot='table-container'][data-sticky-header='true'] thead {
23772
23775
  top: 0;
23773
23776
  }
23774
23777
 
23778
+ /* Table section backgrounds can be clipped to rounded cell boxes by the table
23779
+ painting algorithm. An independent layer also covers those outer corners. */
23780
+ [data-jumpy-theme='true'] [data-jumpy-slot='table-container'][data-sticky-header='true'] thead::before,
23781
+ [data-jumpy-theme='true'] [data-jumpy-slot='table-container'][data-sticky-header='true'] tfoot::before {
23782
+ content: '';
23783
+ position: absolute;
23784
+ inset: 0;
23785
+ z-index: -1;
23786
+ pointer-events: none;
23787
+ background-color: var(--jumpy-cmp-table-backdrop-color);
23788
+ }
23789
+
23790
+ [data-jumpy-theme='true'] [data-jumpy-slot='table-container'][data-sticky-header='true'] :is(thead, tfoot) > [data-jumpy-component='table-row'] > :is([data-jumpy-component='table-cell'], [data-jumpy-component='table-header-cell']):is(:first-child, :last-child) {
23791
+ /* Only the decorative surface is rounded; sticky backdrops are rectangular. */
23792
+ border-radius: 0;
23793
+ }
23794
+
23775
23795
  [data-jumpy-theme='true'] [data-jumpy-slot='table-container'][data-sticky-header='true'] tfoot {
23776
23796
  bottom: 0;
23777
23797
  }
package/dist/index.js CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  textStyleValue,
29
29
  themeToCSSVariables,
30
30
  useJumpyTheme
31
- } from "./chunk-KIZKZXWH.js";
31
+ } from "./chunk-HQ4NWZ65.js";
32
32
  import {
33
33
  cn
34
34
  } from "./chunk-3DBKYKP2.js";
@@ -680,7 +680,6 @@ function JumpListItem({ as, children, className = "", selected = false, disabled
680
680
  const isDisabled = disabled || readOnly;
681
681
  const bodyMedium = textStyleValue(theme, JumpyTextStyle.bodyMedium);
682
682
  const bodySmall = textStyleValue(theme, JumpyTextStyle.bodySmall);
683
- const bodyMediumEmphasized = textStyleValue(theme, JumpyTextStyle.bodyMediumEmphasized);
684
683
  const iconSize = sizeValue(theme, JumpySize.small2XS);
685
684
  const handleExpandedChange = () => {
686
685
  const nextCollapsed = !isNestedCollapsed;
@@ -750,7 +749,7 @@ function JumpListItem({ as, children, className = "", selected = false, disabled
750
749
  resolvedSelector ? /* @__PURE__ */ jsx("span", { "data-jumpy-slot": "selector", "aria-hidden": props.role === "option" || props.role === "treeitem" ? "true" : void 0, className: innerClasses.selector?.className, style: { display: "inline-flex", pointerEvents: "none", color: "var(--jumpy-list-item-icon-color, var(--jumpy-list-item-default-icon))", ...innerClasses.selector?.style || {} }, children: resolvedSelector }) : null,
751
750
  resolvedLeading ? /* @__PURE__ */ jsx("span", { "data-jumpy-slot": "leading", "aria-hidden": "true", className: innerClasses.leading?.className, style: { display: "inline-flex", width: iconSize, height: iconSize, color: "var(--jumpy-list-item-icon-color, var(--jumpy-list-item-default-icon))", ...innerClasses.leading?.style || {} }, children: resolvedLeading }) : null,
752
751
  /* @__PURE__ */ jsxs("span", { style: { display: "grid", minWidth: 0 }, children: [
753
- /* @__PURE__ */ jsx("span", { "data-jumpy-slot": "label", "data-truncate": truncateTexts ? "true" : void 0, "data-text": typeof children === "string" ? children : void 0, className: innerClasses.label?.className, style: { minWidth: 0, maxWidth: "100%", overflowWrap: "anywhere", wordBreak: "break-word", fontWeight: selected ? bodyMediumEmphasized.fontWeight : bodyMedium.fontWeight, ...innerClasses.label?.style || {} }, children }),
752
+ /* @__PURE__ */ jsx("span", { "data-jumpy-slot": "label", "data-truncate": truncateTexts ? "true" : void 0, "data-text": typeof children === "string" ? children : void 0, className: innerClasses.label?.className, style: { minWidth: 0, maxWidth: "100%", overflowWrap: "anywhere", wordBreak: "break-word", fontWeight: bodyMedium.fontWeight, ...innerClasses.label?.style || {} }, children }),
754
753
  resolvedDescription ? /* @__PURE__ */ jsx("span", { "data-jumpy-slot": "description", className: innerClasses.description?.className, style: { color: selected ? theme.listItem.active.default.subtext : theme.listItem.inactive.default.subtext, fontSize: bodySmall.fontSize, lineHeight: bodySmall.lineHeight, ...innerClasses.description?.style || {} }, children: resolvedDescription }) : null
755
754
  ] }),
756
755
  resolvedMetadata ? /* @__PURE__ */ jsx("span", { "data-jumpy-slot": "metadata", className: innerClasses.metadata?.className, style: { color: selected ? theme.listItem.active.default.subtext : theme.listItem.inactive.default.subtext, whiteSpace: "nowrap", fontSize: bodySmall.fontSize, lineHeight: bodySmall.lineHeight, ...innerClasses.metadata?.style || {} }, children: resolvedMetadata }) : null,
@@ -1770,7 +1769,7 @@ function JumpTableCell({ as, children, selected = false, disabled = false, align
1770
1769
  /* @__PURE__ */ jsxs("span", { "data-jumpy-slot": "table-cell-inner", "data-align": resolvedAlign, className: innerClasses.inner?.className, style: innerClasses.inner?.style, children: [
1771
1770
  cellLeading ? /* @__PURE__ */ jsx("span", { "data-jumpy-slot": "table-cell-leading", className: innerClasses.leading?.className, style: innerClasses.leading?.style, children: cellLeading }) : null,
1772
1771
  /* @__PURE__ */ jsxs("span", { "data-jumpy-slot": "table-cell-content", className: innerClasses.content?.className, style: innerClasses.content?.style, children: [
1773
- /* @__PURE__ */ jsx("span", { "data-jumpy-slot": "table-cell-text", className: innerClasses.text?.className, style: tableCellTextStyle(theme, selected, innerClasses.text?.style), children }),
1772
+ /* @__PURE__ */ jsx("span", { "data-jumpy-slot": "table-cell-text", className: innerClasses.text?.className, style: tableCellTextStyle(theme, false, innerClasses.text?.style), children }),
1774
1773
  cellDescription ? /* @__PURE__ */ jsx("span", { "data-jumpy-slot": "table-cell-description", className: innerClasses.description?.className, style: tableCellTextStyle(theme, false, innerClasses.description?.style), children: cellDescription }) : null
1775
1774
  ] }),
1776
1775
  cellTrailing ? /* @__PURE__ */ jsx("span", { "data-jumpy-slot": "table-cell-trailing", className: innerClasses.trailing?.className, style: innerClasses.trailing?.style, children: cellTrailing }) : null
@@ -3044,11 +3043,14 @@ function JumpLoader({ label = "Jumpy UI wird geladen", fullScreen = false, class
3044
3043
  /* @__PURE__ */ jsx(JumpCard, { className: cn("px-10 py-9", decorativeBackground && "relative z-10"), children: content })
3045
3044
  ] });
3046
3045
  }
3047
- function JumpButton({ as, variant = "primary", status = "regular", className = "", isLoading = false, disabled, elevated = false, slots, leadingIcon, trailingIcon, children, ...props }) {
3046
+ function JumpButton({ as, size: size2, variant = "primary", status = "regular", className = "", isLoading = false, disabled, elevated = false, slots, leadingIcon, trailingIcon, children, ...props }) {
3048
3047
  const theme = useJumpyTheme();
3049
3048
  const variantStyles = getButtonVariantStyles(theme, variant, status);
3050
- const bodyMediumEmphasized = textStyleValue(theme, JumpyTextStyle.bodyMediumEmphasized);
3051
- const iconSize = sizeValue(theme, JumpySize.small2XS);
3049
+ const height = sizeValue(theme, size2 ?? JumpySize.large);
3050
+ if (!Number.isFinite(height) || height < 0) throw new Error(`Invalid JumpButton size token: ${size2}`);
3051
+ const compact = height < sizeValue(theme, JumpySize.large);
3052
+ const textStyle = textStyleValue(theme, compact ? JumpyTextStyle.bodySmallEmphasized : JumpyTextStyle.bodyMediumEmphasized);
3053
+ const iconSize = sizeValue(theme, compact ? JumpySize.small3XS : JumpySize.small2XS);
3052
3054
  const [pressed, setPressed] = useState(false);
3053
3055
  const leading = slots?.leading ?? leadingIcon;
3054
3056
  const trailing = slots?.trailing ?? trailingIcon;
@@ -3057,6 +3059,15 @@ function JumpButton({ as, variant = "primary", status = "regular", className = "
3057
3059
  const isDisabled = disabled || isLoading;
3058
3060
  const spacing = getButtonSpacing(theme, variant, Boolean(leading), Boolean(trailing));
3059
3061
  const hasBorder = variant === "secondary" || variant === "tertiary";
3062
+ if (size2 !== void 0) {
3063
+ const border = hasBorder ? borderWidthValue(theme, JumpyBorderWidth.small) : 0;
3064
+ const contentHeight = Math.max(textStyle.fontSize * textStyle.lineHeight, leading || trailing ? iconSize : 0);
3065
+ spacing.paddingTop = spacing.paddingBottom = Math.max(0, (height - contentHeight - border * 2) / 2);
3066
+ if (compact) {
3067
+ spacing.gap = spacingValue(theme, JumpySpacing.small3XS);
3068
+ spacing.paddingLeft = spacing.paddingRight = spacingValue(theme, variant === "borderless" ? JumpySpacing.zero : JumpySpacing.medium);
3069
+ }
3070
+ }
3060
3071
  const content = /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", flexDirection: "row", alignItems: "center", justifyContent: "center", gap: spacing.gap, whiteSpace: "nowrap" }, children: [
3061
3072
  leading ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "inline-flex shrink-0 items-center justify-center", style: { width: iconSize, height: iconSize, lineHeight: 0, fontSize: iconSize }, children: leading }) : null,
3062
3073
  /* @__PURE__ */ jsx("span", { children }),
@@ -3072,6 +3083,7 @@ function JumpButton({ as, variant = "primary", status = "regular", className = "
3072
3083
  "data-status": status,
3073
3084
  "data-elevated": elevated ? "true" : "false",
3074
3085
  "data-loading": isLoading ? "true" : "false",
3086
+ "data-size": size2,
3075
3087
  "data-pressed": pressed ? "true" : "false",
3076
3088
  "aria-busy": isLoading || void 0,
3077
3089
  "aria-disabled": !isButton && isDisabled ? true : props["aria-disabled"],
@@ -3098,7 +3110,7 @@ function JumpButton({ as, variant = "primary", status = "regular", className = "
3098
3110
  display: "inline-flex",
3099
3111
  alignItems: "center",
3100
3112
  justifyContent: "center",
3101
- minHeight: sizeValue(theme, JumpySize.large),
3113
+ minHeight: height,
3102
3114
  appearance: "none",
3103
3115
  WebkitAppearance: "none",
3104
3116
  boxSizing: "border-box",
@@ -3107,11 +3119,11 @@ function JumpButton({ as, variant = "primary", status = "regular", className = "
3107
3119
  paddingTop: spacing.paddingTop,
3108
3120
  paddingBottom: spacing.paddingBottom,
3109
3121
  borderRadius: radiusValue(theme, JumpyRadius.small),
3110
- letterSpacing: bodyMediumEmphasized.letterSpacing,
3122
+ letterSpacing: textStyle.letterSpacing,
3111
3123
  fontFamily: theme.fontFamily.familyBase,
3112
- fontSize: bodyMediumEmphasized.fontSize,
3113
- lineHeight: bodyMediumEmphasized.lineHeight,
3114
- fontWeight: bodyMediumEmphasized.fontWeight,
3124
+ fontSize: textStyle.fontSize,
3125
+ lineHeight: textStyle.lineHeight,
3126
+ fontWeight: textStyle.fontWeight,
3115
3127
  opacity: isDisabled ? opacityValue(theme, JumpyOpacity.medium) : opacityValue(theme, JumpyOpacity.solid),
3116
3128
  borderWidth: hasBorder ? borderWidthValue(theme, JumpyBorderWidth.small) : 0,
3117
3129
  borderStyle: hasBorder ? "solid" : "none",
package/dist/theme.js CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  textStyleValue,
29
29
  themeToCSSVariables,
30
30
  useJumpyTheme
31
- } from "./chunk-KIZKZXWH.js";
31
+ } from "./chunk-HQ4NWZ65.js";
32
32
  export {
33
33
  JumpyAnimation,
34
34
  JumpyAnimationDelay,
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { AnchorHTMLAttributes, ButtonHTMLAttributes, HTMLAttributes, InputHTMLAttributes, ReactNode, Ref, TdHTMLAttributes, TextareaHTMLAttributes, ThHTMLAttributes } from 'react'
2
- export type { JumpyTheme } from './theme.js'
2
+ export type { JumpyTheme, JumpySizeToken } from './theme.js'
3
3
  type ElementTag = keyof HTMLElementTagNameMap
4
4
  type JumpResponsiveValue<T> = T | { small?: T; medium?: T; large?: T; xLarge?: T }
5
5
  type JumpGridSpacing = number | string | [row: number | string, column: number | string]
@@ -128,7 +128,7 @@ export type JumpDialogInnerPart = 'illustration' | 'body' | 'icon' | 'title' | '
128
128
  export type JumpDialogInnerClasses = Partial<Record<JumpDialogInnerPart, { className?: string; style?: import('react').CSSProperties }>>
129
129
  export declare function JumpDialog(props: HTMLAttributes<HTMLElement> & { as?: ElementTag; visible?: boolean; onVisibleChange?: (visible: boolean) => void; title?: ReactNode; description?: ReactNode; footer?: ReactNode; disableBackdropClick?: boolean; disableContentScroll?: boolean; fullScreen?: boolean; overlayProps?: HTMLAttributes<HTMLDivElement>; slots?: { illustration?: ReactNode; icon?: ReactNode; title?: ReactNode; description?: ReactNode; footer?: ReactNode }; innerClasses?: JumpDialogInnerClasses; children?: ReactNode }): ReactNode
130
130
  export declare function JumpLoader(props: { label?: string; fullScreen?: boolean; className?: string; decorativeBackground?: boolean }): ReactNode
131
- export declare function JumpButton(props: JumpPolymorphicButtonAttributes & { as?: ElementTag; variant?: 'primary' | 'secondary' | 'tertiary' | 'borderless'; status?: 'regular' | 'alarm'; isLoading?: boolean; elevated?: boolean; slots?: JumpButtonSlots; leadingIcon?: ReactNode; trailingIcon?: ReactNode }): ReactNode
131
+ export declare function JumpButton(props: JumpPolymorphicButtonAttributes & { as?: ElementTag; size?: import('./theme.js').JumpySizeToken; variant?: 'primary' | 'secondary' | 'tertiary' | 'borderless'; status?: 'regular' | 'alarm'; isLoading?: boolean; elevated?: boolean; slots?: JumpButtonSlots; leadingIcon?: ReactNode; trailingIcon?: ReactNode }): ReactNode
132
132
  export declare function JumpIconButton(props: JumpPolymorphicButtonAttributes & { as?: ElementTag; variant?: 'primary' | 'secondary' | 'tertiary' | 'borderless'; status?: 'regular' | 'alarm'; alternateHover?: boolean; elevated?: boolean }): ReactNode
133
133
  export declare function JumpLinkButton(props: AnchorHTMLAttributes<HTMLAnchorElement> & { href: string; variant?: 'primary' | 'secondary' | 'tertiary' | 'borderless'; status?: 'regular' | 'alarm'; leadingIcon?: ReactNode; trailingIcon?: ReactNode }): ReactNode
134
134
  export declare const JumpInput: import('react').ForwardRefExoticComponent<InputHTMLAttributes<HTMLInputElement> & { status?: JumpInputStatus } & import('react').RefAttributes<HTMLInputElement>>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mario_hahn/jumpy-ui",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
package/theme.d.ts CHANGED
@@ -19,7 +19,8 @@ export type JumpyTheme = {
19
19
  }
20
20
 
21
21
  export declare const JumpySpacing: Record<string, string>
22
- export declare const JumpySize: Record<string, string>
22
+ export type JumpySizeToken = 'none' | 'small5XS' | 'small4XS' | 'small3XS' | 'small2XS' | 'smallXS' | 'small' | 'medium' | 'large' | 'largeXL' | 'large2XL' | 'large3XL' | 'large4XL' | 'large5XL' | 'large6XL' | 'large7XL' | 'large8XL'
23
+ export declare const JumpySize: { readonly [Key in JumpySizeToken]: Key }
23
24
  export declare const JumpyRadius: Record<string, string>
24
25
  export declare const JumpyOpacity: Record<string, string>
25
26
  export declare const JumpyBorderWidth: Record<string, string>