@mario_hahn/jumpy-ui 0.14.3 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -162,7 +162,15 @@ behind the decorative cell surfaces. The default resolves to the opaque semantic
162
162
  card surface in each preset. Normal cell decorations are transparent; selected
163
163
  and hovered cells use their semantic interaction surfaces. The scroll container
164
164
  and pinned cells share the same backdrop. Keep any custom backdrop override opaque.
165
- Use `showHorizontalBorders` for explicit row separators in all columns.
165
+ Use `showHorizontalBorders` for explicit row separators in all columns. Separators lie
166
+ between rows: the last body row has none, unless a `JumpTableFooter` follows (the footer
167
+ draws its own top border).
168
+
169
+ `surface="card"` (default) paints the backdrop box described above, right inside a
170
+ `JumpCard`. On a plain page use `<JumpTable surface="none">`: no card box, square corners
171
+ or inset rows. Sticky headers and pinned cells still need an opaque backdrop, so it falls
172
+ back to the page canvas (`--jumpy-color-surface-canvas`); if the page uses another
173
+ background, set `--jumpy-cmp-table-backdrop-color` to it.
166
174
 
167
175
  `JumpTableCell` and `JumpTableHeaderCell` support `pinned="left"` or `pinned="right"`;
168
176
  use `pinnedEdge` for the edge divider. Pinned cells use the same backdrop as the
@@ -14703,6 +14703,15 @@ var providerStyles = `
14703
14703
  width: 100%;
14704
14704
  }
14705
14705
 
14706
+ /* surface="none": no card box. Sticky headers and pinned cells still need an opaque backdrop, so it falls back to the page canvas. */
14707
+ [data-jumpy-theme='true'] [data-jumpy-slot='table-wrapper'][data-surface='none'] {
14708
+ --jumpy-cmp-table-backdrop-color: var(--jumpy-color-surface-canvas);
14709
+ }
14710
+
14711
+ [data-jumpy-theme='true'] [data-jumpy-slot='table-wrapper'][data-surface='none'] > [data-jumpy-slot='table-container'] {
14712
+ background-color: transparent;
14713
+ }
14714
+
14706
14715
  [data-jumpy-theme='true'] [data-jumpy-slot='table-container'] {
14707
14716
  display: block;
14708
14717
  position: relative;
@@ -14848,6 +14857,11 @@ var providerStyles = `
14848
14857
  display: none;
14849
14858
  }
14850
14859
 
14860
+ /* Row separators lie between rows: the last body row has none unless a footer follows (it draws its own top border). */
14861
+ [data-jumpy-theme='true'] [data-jumpy-component='table'] > [data-jumpy-component='table-body']:last-child > [data-jumpy-component='table-row']:last-child > [data-jumpy-component='table-cell']::before {
14862
+ display: none;
14863
+ }
14864
+
14851
14865
  [data-jumpy-theme='true'] [data-jumpy-component='table-cell']:first-child::before,
14852
14866
  [data-jumpy-theme='true'] [data-jumpy-component='table-header-cell']:first-child::before {
14853
14867
  inset-inline-start: var(--jumpy-spacing-size-4xsmall);
@@ -16644,18 +16658,18 @@ function createCardTokens(theme) {
16644
16658
  if (presetCard?.inactive && presetCard?.active) {
16645
16659
  return {
16646
16660
  inactive: {
16647
- default: normalizeTokenState(presetCard.inactive.default),
16648
- hover: normalizeTokenState(presetCard.inactive.hover),
16649
- pressed: normalizeTokenState(presetCard.inactive.pressed),
16650
- focus: normalizeTokenState(presetCard.inactive.focus),
16651
- disabled: normalizeTokenState(presetCard.inactive.disabled)
16661
+ default: resolveGeneratedState(presetCard.inactive.default, "card-inactive-default", theme),
16662
+ hover: resolveGeneratedState(presetCard.inactive.hover, "card-inactive-hover", theme),
16663
+ pressed: resolveGeneratedState(presetCard.inactive.pressed, "card-inactive-pressed", theme),
16664
+ focus: resolveGeneratedState(presetCard.inactive.focus, "card-inactive-focus", theme),
16665
+ disabled: resolveGeneratedState(presetCard.inactive.disabled, "card-inactive-disabled", theme)
16652
16666
  },
16653
16667
  active: {
16654
- default: normalizeTokenState(presetCard.active.default),
16655
- hover: normalizeTokenState(presetCard.active.hover),
16656
- pressed: normalizeTokenState(presetCard.active.pressed),
16657
- focus: normalizeTokenState(presetCard.active.focus),
16658
- disabled: normalizeTokenState(presetCard.active.disabled)
16668
+ default: resolveGeneratedState(presetCard.active.default, "card-active-default", theme),
16669
+ hover: resolveGeneratedState(presetCard.active.hover, "card-active-hover", theme),
16670
+ pressed: resolveGeneratedState(presetCard.active.pressed, "card-active-pressed", theme),
16671
+ focus: resolveGeneratedState(presetCard.active.focus, "card-active-focus", theme),
16672
+ disabled: resolveGeneratedState(presetCard.active.disabled, "card-active-disabled", theme)
16659
16673
  }
16660
16674
  };
16661
16675
  }
@@ -16683,18 +16697,18 @@ function createListItemTokens(theme) {
16683
16697
  if (presetInactiveRegular && presetActiveRegular) {
16684
16698
  return {
16685
16699
  inactive: {
16686
- default: normalizeTokenState(presetInactiveRegular.default),
16687
- hover: normalizeTokenState(presetInactiveRegular.hover),
16688
- pressed: normalizeTokenState(presetInactiveRegular.pressed),
16689
- focus: normalizeTokenState(presetInactiveRegular.focus),
16690
- disabled: normalizeTokenState(presetInactiveRegular.disabled)
16700
+ default: resolveGeneratedState(presetInactiveRegular.default, "interactive-inactive-regular-default", theme),
16701
+ hover: resolveGeneratedState(presetInactiveRegular.hover, "interactive-inactive-regular-hover", theme),
16702
+ pressed: resolveGeneratedState(presetInactiveRegular.pressed, "interactive-inactive-regular-pressed", theme),
16703
+ focus: resolveGeneratedState(presetInactiveRegular.focus, "interactive-inactive-regular-focus", theme),
16704
+ disabled: resolveGeneratedState(presetInactiveRegular.disabled, "interactive-inactive-regular-disabled", theme)
16691
16705
  },
16692
16706
  active: {
16693
- default: normalizeTokenState(presetActiveRegular.default),
16694
- hover: normalizeTokenState(presetActiveRegular.hover),
16695
- pressed: normalizeTokenState(presetActiveRegular.pressed),
16696
- focus: normalizeTokenState(presetActiveRegular.focus),
16697
- disabled: normalizeTokenState(presetActiveRegular.disabled)
16707
+ default: resolveGeneratedState(presetActiveRegular.default, "interactive-active-regular-default", theme),
16708
+ hover: resolveGeneratedState(presetActiveRegular.hover, "interactive-active-regular-hover", theme),
16709
+ pressed: resolveGeneratedState(presetActiveRegular.pressed, "interactive-active-regular-pressed", theme),
16710
+ focus: resolveGeneratedState(presetActiveRegular.focus, "interactive-active-regular-focus", theme),
16711
+ disabled: resolveGeneratedState(presetActiveRegular.disabled, "interactive-active-regular-disabled", theme)
16698
16712
  }
16699
16713
  };
16700
16714
  }
@@ -16715,25 +16729,41 @@ function createListItemTokens(theme) {
16715
16729
  }
16716
16730
  };
16717
16731
  }
16732
+ function resolveGeneratedState(state, prefix, theme) {
16733
+ const normalized = normalizeTokenState(state);
16734
+ if (!normalized) return normalized;
16735
+ const sources = { ...color_sources_default.base, ...color_sources_default.presets?.[theme.__tokenPresetName || "default-light"] };
16736
+ const slots = { surface: "surface", border: "border", text: "text", subtext: "subtext", icon: "icon", handle: "handle", focusRing: "focus-ring", hoverRing: "hover-ring" };
16737
+ const resolved = { ...normalized };
16738
+ for (const [slot, cssSlot] of Object.entries(slots)) {
16739
+ const source = sources[`jumpy-${prefix}-${cssSlot}`];
16740
+ if (source && theme.color?.[source] !== void 0) resolved[slot] = theme.color[source];
16741
+ }
16742
+ return resolved;
16743
+ }
16744
+ function resolveSelectorState(state, group, name, theme) {
16745
+ return resolveGeneratedState(state, `selectors-${group}-${name}`, theme);
16746
+ }
16718
16747
  function createSelectorTokens(theme) {
16719
16748
  const presetSelectors = getWebPresetTokenRoot(theme.__tokenPresetName || "default-light")?.selectors;
16720
16749
  if (presetSelectors?.inactive && presetSelectors?.active) {
16750
+ const state = (group, name, key = name) => resolveSelectorState(presetSelectors[group][key], group, name, theme);
16721
16751
  return {
16722
16752
  inactive: {
16723
- default: normalizeTokenState(presetSelectors.inactive.default),
16724
- disabled: normalizeTokenState(presetSelectors.inactive.disabled),
16725
- focus: normalizeTokenState(presetSelectors.inactive.focus),
16726
- hover: normalizeTokenState(presetSelectors.inactive.hover),
16727
- pressed: normalizeTokenState(presetSelectors.inactive.pressed),
16728
- readOnly: normalizeTokenState(presetSelectors.inactive.read?.only)
16753
+ default: state("inactive", "default"),
16754
+ disabled: state("inactive", "disabled"),
16755
+ focus: state("inactive", "focus"),
16756
+ hover: state("inactive", "hover"),
16757
+ pressed: state("inactive", "pressed"),
16758
+ readOnly: resolveSelectorState(presetSelectors.inactive.read?.only, "inactive", "read-only", theme)
16729
16759
  },
16730
16760
  active: {
16731
- default: normalizeTokenState(presetSelectors.active.default),
16732
- disabled: normalizeTokenState(presetSelectors.active.disabled),
16733
- focus: normalizeTokenState(presetSelectors.active.focus),
16734
- hover: normalizeTokenState(presetSelectors.active.hover),
16735
- pressed: normalizeTokenState(presetSelectors.active.pressed),
16736
- readOnly: normalizeTokenState(presetSelectors.active.read?.only)
16761
+ default: state("active", "default"),
16762
+ disabled: state("active", "disabled"),
16763
+ focus: state("active", "focus"),
16764
+ hover: state("active", "hover"),
16765
+ pressed: state("active", "pressed"),
16766
+ readOnly: resolveSelectorState(presetSelectors.active.read?.only, "active", "read-only", theme)
16737
16767
  }
16738
16768
  };
16739
16769
  }
@@ -18,7 +18,7 @@ import {
18
18
  textStyleValue,
19
19
  themeToCSSVariables,
20
20
  useJumpyTheme
21
- } from "./chunk-73UN7NZJ.js";
21
+ } from "./chunk-5YSWJIM2.js";
22
22
  import {
23
23
  cn
24
24
  } from "./chunk-3DBKYKP2.js";
@@ -1696,10 +1696,10 @@ function JumpSnackbarProvider({ children, position = "bottom-center", maxSnackba
1696
1696
  /* @__PURE__ */ jsx("div", { ...props, "data-jumpy-component": "snackbar-provider", className: cn(className), style: { position: "fixed", zIndex: 1100, left: position.endsWith("start") ? horizontalOffset : position.endsWith("end") ? "auto" : "50%", right: position.endsWith("end") ? horizontalOffset : "auto", top: top ? verticalOffset : "auto", bottom: top ? "auto" : verticalOffset, transform: position.endsWith("center") ? "translateX(-50%)" : void 0, display: "flex", flexDirection: "column", alignItems: align, gap: spacingValue(theme, JumpySpacing.smallXS), width: "min(487px, calc(100vw - 32px))", maxWidth: "50vw", pointerEvents: "none", ...props.style || {} }, children: snackbars.map((snackbar) => snackbar.isData ? /* @__PURE__ */ jsx(JumpBanner, { floating: true, status: snackbar.content.status || "info", title: snackbar.content.title, actions: snackbar.content.slots?.actions, style: { width: "100%", pointerEvents: "auto", boxShadow: theme.shadow.positiveLarge }, children: snackbar.content.description }, snackbar.id) : /* @__PURE__ */ jsx("div", { "data-jumpy-component": "snackbar", style: { width: "100%", pointerEvents: "auto", borderRadius: radiusValue(theme, JumpyRadius.small), boxShadow: theme.shadow.positiveLarge }, children: snackbar.content }, snackbar.id)) })
1697
1697
  ] });
1698
1698
  }
1699
- function JumpTable({ children, showHorizontalBorders = false, disabled = false, stickyHeader = false, density = "regular", containerProps, innerClasses = {}, className = "", ...props }) {
1699
+ function JumpTable({ children, showHorizontalBorders = false, disabled = false, stickyHeader = false, density = "regular", surface = "card", containerProps, innerClasses = {}, className = "", ...props }) {
1700
1700
  const { className: containerClassName, style: containerStyle, ...restContainerProps } = containerProps || {};
1701
1701
  const contextValue = { showHorizontalBorders, disabled };
1702
- return /* @__PURE__ */ jsx(JumpyTableContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { "data-jumpy-slot": "table-wrapper", className: innerClasses.wrapper?.className, style: innerClasses.wrapper?.style, children: /* @__PURE__ */ jsx("div", { ...restContainerProps, "data-jumpy-slot": "table-container", "data-sticky-header": stickyHeader ? "true" : "false", className: cn(containerClassName), style: containerStyle, children: /* @__PURE__ */ jsx("table", { ...props, "data-jumpy-component": "table", "data-horizontal-borders": showHorizontalBorders ? "true" : "false", "data-density": density === "condensed" ? "condensed" : void 0, "data-disabled": disabled ? "true" : void 0, role: props.role || "grid", className: cn(className), children }) }) }) });
1702
+ return /* @__PURE__ */ jsx(JumpyTableContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { "data-jumpy-slot": "table-wrapper", "data-surface": surface === "none" ? "none" : void 0, className: innerClasses.wrapper?.className, style: innerClasses.wrapper?.style, children: /* @__PURE__ */ jsx("div", { ...restContainerProps, "data-jumpy-slot": "table-container", "data-sticky-header": stickyHeader ? "true" : "false", className: cn(containerClassName), style: containerStyle, children: /* @__PURE__ */ jsx("table", { ...props, "data-jumpy-component": "table", "data-horizontal-borders": showHorizontalBorders ? "true" : "false", "data-density": density === "condensed" ? "condensed" : void 0, "data-disabled": disabled ? "true" : void 0, role: props.role || "grid", className: cn(className), children }) }) }) });
1703
1703
  }
1704
1704
  function JumpTableHead({ as, children, className = "", ...props }) {
1705
1705
  const Component = as || "thead";
@@ -2401,7 +2401,8 @@ ${shell} [data-jumpy-slot='app-shell-actions'][data-variant='compact'] { display
2401
2401
  ${shell} [data-jumpy-slot='app-shell-actions'][data-variant='full'] { display: none; }
2402
2402
  ${shell} [data-jumpy-slot='app-shell-back'][data-variant='inline'] { display: none; }
2403
2403
  @media (min-width: ${breakpoint}px) {
2404
- ${shell} { grid-template-columns: ${width} minmax(0, 1fr); }
2404
+ ${shell} { grid-template-columns: ${width} minmax(0, 1fr); }${topBarOnDesktop ? "" : `
2405
+ ${shell} { --jumpy-app-shell-large-title-padding-top: ${spacingValue(theme, JumpySpacing.large2XL)}px; }`}
2405
2406
  ${shell} > [data-jumpy-slot='app-shell-sidebar'] { display: flex; }
2406
2407
  ${shell} [data-jumpy-slot='app-shell-actions'][data-variant='compact'] { display: none; }
2407
2408
  ${shell} [data-jumpy-slot='app-shell-actions'][data-variant='full'] { display: inline-flex; }
@@ -2476,7 +2477,7 @@ ${shell} [data-jumpy-slot='app-shell-back'][data-variant='inline'] { display: no
2476
2477
  /* @__PURE__ */ jsxs("div", { "data-jumpy-slot": "app-shell-body", style: { display: "flex", flexDirection: "column", minWidth: 0, minHeight: "100dvh" }, children: [
2477
2478
  topBar !== null ? topBarNode : null,
2478
2479
  /* @__PURE__ */ jsxs("main", { "data-jumpy-slot": "app-shell-content", style: { flex: 1, minWidth: 0 }, children: [
2479
- showLargeTitle ? /* @__PURE__ */ jsx("div", { "data-jumpy-slot": "app-shell-large-title", style: { padding: `${spacingValue(theme, JumpySpacing.smallXS)}px calc(var(--jumpy-app-shell-gutter, ${spacingValue(theme, JumpySpacing.large)}px) + env(safe-area-inset-right, 0px)) 0 calc(var(--jumpy-app-shell-gutter, ${spacingValue(theme, JumpySpacing.large)}px) + env(safe-area-inset-left, 0px))` }, children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "flex-end", justifyContent: "space-between", gap: spacingValue(theme, JumpySpacing.large), flexWrap: "wrap" }, children: [
2480
+ showLargeTitle ? /* @__PURE__ */ jsx("div", { "data-jumpy-slot": "app-shell-large-title", style: { padding: `var(--jumpy-app-shell-large-title-padding-top, ${spacingValue(theme, JumpySpacing.smallXS)}px) calc(var(--jumpy-app-shell-gutter, ${spacingValue(theme, JumpySpacing.large)}px) + env(safe-area-inset-right, 0px)) 0 calc(var(--jumpy-app-shell-gutter, ${spacingValue(theme, JumpySpacing.large)}px) + env(safe-area-inset-left, 0px))` }, children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "flex-end", justifyContent: "space-between", gap: spacingValue(theme, JumpySpacing.large), flexWrap: "wrap" }, children: [
2480
2481
  /* @__PURE__ */ jsxs("div", { style: { minWidth: 0 }, children: [
2481
2482
  hasBack ? /* @__PURE__ */ jsx(JumpyAppShellBack, { back, variant: "inline", ariaLabels }) : null,
2482
2483
  /* @__PURE__ */ jsx("h1", { ref: largeTitleRef, style: { margin: 0, ...textStyleValue(theme, JumpyTextStyle.displaySmallEmphasized), overflowWrap: "anywhere" }, children: topBarProps.title }),
@@ -2875,17 +2876,45 @@ function formatTimeValue(value, format = "HH:mm") {
2875
2876
  const hours12 = hours24 % 12 || 12;
2876
2877
  return format.includes("aa") ? format.replace("hh", String(hours12).padStart(2, "0")).replace("mm", minutes).replace("aa", period) : format.replace("HH", String(hours24).padStart(2, "0")).replace("mm", minutes);
2877
2878
  }
2878
- function parseDateValue(text, format = "MM/dd/yyyy") {
2879
+ var MASK_TOKENS = { yyyy: { max: 4 }, MM: { max: 2, padAbove: "1" }, dd: { max: 2, padAbove: "3" }, HH: { max: 2, padAbove: "2" }, mm: { max: 2, padAbove: "5" } };
2880
+ function maskDigitsToFormat(text, format) {
2881
+ const digits = text.replace(/\D/g, "");
2882
+ const typedSeparator = /\D$/.test(text);
2883
+ const parts = format.split(/(yyyy|MM|dd|HH|mm)/).filter(Boolean);
2884
+ let out = "";
2885
+ let index = 0;
2886
+ for (let i = 0; i < parts.length; i += 1) {
2887
+ const rule = MASK_TOKENS[parts[i]];
2888
+ if (!rule) continue;
2889
+ if (index >= digits.length) break;
2890
+ let chunk;
2891
+ if (rule.padAbove && digits[index] > rule.padAbove) {
2892
+ chunk = `0${digits[index]}`;
2893
+ index += 1;
2894
+ } else {
2895
+ chunk = digits.slice(index, index + rule.max);
2896
+ index += chunk.length;
2897
+ if (rule.padAbove && chunk.length === 1 && typedSeparator && index === digits.length) chunk = `0${chunk}`;
2898
+ }
2899
+ out += chunk;
2900
+ if (chunk.length < rule.max) break;
2901
+ const next = parts.findIndex((part, position) => position > i && MASK_TOKENS[part]);
2902
+ if (next !== -1 && (index < digits.length || typedSeparator)) out += parts.slice(i + 1, next).join("");
2903
+ }
2904
+ return out;
2905
+ }
2906
+ function parseDateValue(text, format = "MM/dd/yyyy", { shortYear = false } = {}) {
2879
2907
  const value = text.trim();
2880
2908
  if (!value) return null;
2881
2909
  const activeFormat = Array.isArray(format) ? format[0] : format;
2882
2910
  const escaped = activeFormat.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2883
- const pattern = escaped.replace("dd", "(?<dd>\\d{1,2})").replace("MM", "(?<MM>\\d{1,2})").replace("yyyy", "(?<yyyy>\\d{4})");
2911
+ const pattern = escaped.replace("dd", "(?<dd>\\d{1,2})").replace("MM", "(?<MM>\\d{1,2})").replace("yyyy", shortYear ? "(?<yyyy>\\d{4}|\\d{2})" : "(?<yyyy>\\d{4})");
2884
2912
  const match = value.match(new RegExp(`^${pattern}$`));
2885
2913
  if (!match?.groups) return null;
2886
2914
  const day = Number(match.groups.dd);
2887
2915
  const month = Number(match.groups.MM) - 1;
2888
- const year = Number(match.groups.yyyy);
2916
+ let year = Number(match.groups.yyyy);
2917
+ if (match.groups.yyyy.length === 2) year += year <= (/* @__PURE__ */ new Date()).getFullYear() % 100 + 10 ? 2e3 : 1900;
2889
2918
  const date = new Date(year, month, day);
2890
2919
  return date.getFullYear() === year && date.getMonth() === month && date.getDate() === day ? date : null;
2891
2920
  }
@@ -3003,12 +3032,14 @@ function JumpDatePicker({ label = "Date", hint, value, defaultValue = null, onCh
3003
3032
  readOnly,
3004
3033
  disabled,
3005
3034
  "data-has-value": selectedTime !== null,
3035
+ "data-jumpy-floating": isOpen,
3006
3036
  value: draft,
3007
3037
  placeholder: props.placeholder || (Array.isArray(format) ? format[0] : format),
3008
3038
  autoComplete: "off",
3009
3039
  inputMode: "numeric",
3010
3040
  onChange: (event) => {
3011
- const text = event.target.value;
3041
+ const typed = event.target.value;
3042
+ const text = typed.length > draft.length && event.target.selectionStart === typed.length ? maskDigitsToFormat(typed, resolvedFormat) || typed : typed;
3012
3043
  setDraft(text);
3013
3044
  const parsedDate = parseDateValue(text, format);
3014
3045
  typedValue.current = void 0;
@@ -3022,7 +3053,15 @@ function JumpDatePicker({ label = "Date", hint, value, defaultValue = null, onCh
3022
3053
  },
3023
3054
  onBlur: (event) => {
3024
3055
  typedValue.current = void 0;
3025
- setDraft(inputValue);
3056
+ const shortDate = parseDateValue(draft, format) ? null : parseDateValue(draft, format, { shortYear: true });
3057
+ if (shortDate && shortDate.getTime() !== selectedTime && !dateIsUnavailable(shortDate, { minDate, maxDate, disabledDates, isDateDisabled })) {
3058
+ const next = coerceDateOutput(shortDate, value ?? defaultValue);
3059
+ setDraft(formatDateValue(shortDate, resolvedFormat));
3060
+ if (!isControlled) setInternalValue(next);
3061
+ onChange?.(next);
3062
+ } else {
3063
+ setDraft(inputValue);
3064
+ }
3026
3065
  props.onBlur?.(event);
3027
3066
  },
3028
3067
  onClick: (event) => {
@@ -3137,12 +3176,14 @@ function JumpTimePicker({ label = "Time", hint, value, defaultValue = null, onCh
3137
3176
  readOnly,
3138
3177
  disabled,
3139
3178
  "data-has-value": selectedTime !== null,
3179
+ "data-jumpy-floating": isOpen,
3140
3180
  value: draft,
3141
3181
  placeholder: props.placeholder || resolvedFormat,
3142
3182
  autoComplete: "off",
3143
3183
  inputMode: resolvedFormat.includes("aa") ? "text" : "numeric",
3144
3184
  onChange: (event) => {
3145
- const text = event.target.value;
3185
+ const typed = event.target.value;
3186
+ const text = !resolvedFormat.includes("aa") && typed.length > draft.length && event.target.selectionStart === typed.length ? maskDigitsToFormat(typed, resolvedFormat) || typed : typed;
3146
3187
  setDraft(text);
3147
3188
  const parsedDate = parseTimeValue(text, resolvedFormat);
3148
3189
  typedValue.current = void 0;
@@ -3889,7 +3930,8 @@ function JumpBaseInput({ label, hint, children, className = "", error = false, h
3889
3930
  const disabled = Boolean(child.props.disabled);
3890
3931
  const isDropdownTrigger = child.props["data-jumpy-dropdown-trigger"] === true || child.props["data-jumpy-dropdown-trigger"] === "true";
3891
3932
  const readOnly = Boolean(child.props.readOnly) && !isDropdownTrigger;
3892
- const floating = focused && !readOnly || hasValue || Boolean(props.slots?.content);
3933
+ const keepFloating = child.props["data-jumpy-floating"] === true || child.props["data-jumpy-floating"] === "true";
3934
+ const floating = focused && !readOnly || hasValue || childHasValue || keepFloating || Boolean(props.slots?.content);
3893
3935
  const isTextarea = child.type === JumpTextarea || child.props["data-jumpy-token-editor"] && child.props.multiline;
3894
3936
  const isDropdown = isDropdownTrigger || child.props["data-jumpy-component"] === "dropdown";
3895
3937
  const status = error ? "alarm" : props.status || "regular";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  JumpField,
3
3
  JumpyFieldContext
4
- } from "./chunk-KSMTJ2AH.js";
4
+ } from "./chunk-UT6U2IMA.js";
5
5
  import {
6
6
  JumpySpacing,
7
7
  spacingValue,
8
8
  useJumpyTheme
9
- } from "./chunk-73UN7NZJ.js";
9
+ } from "./chunk-5YSWJIM2.js";
10
10
 
11
11
  // editor.js
12
12
  import { useContext, useRef as useRef2, useState as useState2 } from "react";
@@ -74,7 +74,7 @@ import {
74
74
  getSortOrder,
75
75
  isRowFullySelected,
76
76
  useJumpSnackbar
77
- } from "./chunk-KSMTJ2AH.js";
77
+ } from "./chunk-UT6U2IMA.js";
78
78
  import {
79
79
  JumpyAnimation,
80
80
  JumpyAnimationDelay,
@@ -105,7 +105,7 @@ import {
105
105
  textStyleValue,
106
106
  themeToCSSVariables,
107
107
  useJumpyTheme
108
- } from "./chunk-73UN7NZJ.js";
108
+ } from "./chunk-5YSWJIM2.js";
109
109
  import "./chunk-3DBKYKP2.js";
110
110
  import {
111
111
  jumpyThemeInventory
package/dist/editor.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import {
3
3
  JumpTokenInput
4
- } from "./chunk-YSO235OL.js";
5
- import "./chunk-KSMTJ2AH.js";
6
- import "./chunk-73UN7NZJ.js";
4
+ } from "./chunk-ZFRDQCPV.js";
5
+ import "./chunk-UT6U2IMA.js";
6
+ import "./chunk-5YSWJIM2.js";
7
7
  import "./chunk-3DBKYKP2.js";
8
8
  import "./chunk-XDTVYUWG.js";
9
9
  export {
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  JumpTokenInput
4
- } from "./chunk-YSO235OL.js";
4
+ } from "./chunk-ZFRDQCPV.js";
5
5
  import {
6
6
  BrandMark,
7
7
  JumpAppShell,
@@ -77,7 +77,7 @@ import {
77
77
  getSortOrder,
78
78
  isRowFullySelected,
79
79
  useJumpSnackbar
80
- } from "./chunk-KSMTJ2AH.js";
80
+ } from "./chunk-UT6U2IMA.js";
81
81
  import {
82
82
  JumpyAnimation,
83
83
  JumpyAnimationDelay,
@@ -108,7 +108,7 @@ import {
108
108
  textStyleValue,
109
109
  themeToCSSVariables,
110
110
  useJumpyTheme
111
- } from "./chunk-73UN7NZJ.js";
111
+ } from "./chunk-5YSWJIM2.js";
112
112
  import "./chunk-3DBKYKP2.js";
113
113
  import {
114
114
  jumpyThemeInventory
package/dist/theme.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  textStyleValue,
31
31
  themeToCSSVariables,
32
32
  useJumpyTheme
33
- } from "./chunk-73UN7NZJ.js";
33
+ } from "./chunk-5YSWJIM2.js";
34
34
  export {
35
35
  JumpyAnimation,
36
36
  JumpyAnimationDelay,
package/index.d.ts CHANGED
@@ -104,7 +104,7 @@ export declare function getRowCheckboxProps(row: JumpSelectableRow, disabled?: b
104
104
  export declare function getHeaderCheckboxProps(table: JumpSelectableTable, disabled?: boolean): JumpSelectionCheckboxProps
105
105
  export type JumpTableInnerClasses = { wrapper?: { className?: string; style?: import('react').CSSProperties } }
106
106
  export type JumpTableCellInnerClasses = Partial<Record<'inner' | 'leading' | 'content' | 'text' | 'description' | 'trailing' | 'label' | 'labelText' | 'sortButton' | 'sortIndicator', { className?: string; style?: import('react').CSSProperties }>>
107
- export declare function JumpTable(props: HTMLAttributes<HTMLTableElement> & { ref?: Ref<HTMLTableElement>; showHorizontalBorders?: boolean; disabled?: boolean; stickyHeader?: boolean; density?: 'default' | 'regular' | 'condensed'; containerProps?: HTMLAttributes<HTMLDivElement> & { ref?: Ref<HTMLDivElement> }; innerClasses?: JumpTableInnerClasses; children?: ReactNode }): ReactNode
107
+ export declare function JumpTable(props: HTMLAttributes<HTMLTableElement> & { ref?: Ref<HTMLTableElement>; showHorizontalBorders?: boolean; disabled?: boolean; stickyHeader?: boolean; density?: 'default' | 'regular' | 'condensed'; surface?: 'card' | 'none'; containerProps?: HTMLAttributes<HTMLDivElement> & { ref?: Ref<HTMLDivElement> }; innerClasses?: JumpTableInnerClasses; children?: ReactNode }): ReactNode
108
108
  export declare function JumpTableHead(props: HTMLAttributes<HTMLTableSectionElement> & { as?: ElementTag; ref?: Ref<HTMLTableSectionElement>; children?: ReactNode }): ReactNode
109
109
  export declare function JumpTableBody(props: HTMLAttributes<HTMLTableSectionElement> & { as?: ElementTag; ref?: Ref<HTMLTableSectionElement>; children?: ReactNode }): ReactNode
110
110
  export declare function JumpTableFooter(props: HTMLAttributes<HTMLTableSectionElement> & { as?: ElementTag; ref?: Ref<HTMLTableSectionElement>; children?: ReactNode }): ReactNode
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mario_hahn/jumpy-ui",
3
- "version": "0.14.3",
3
+ "version": "0.15.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "sideEffects": ["**/*.css"],