@mario_hahn/jumpy-ui 0.8.0 → 0.9.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,11 +1,88 @@
1
1
  # @mario_hahn/jumpy-ui
2
2
 
3
+ ## Text with inline tokens
4
+
5
+ `JumpTokenInput` shares the normal field shell, labels, hints, focus and alarm
6
+ styles, but its value is structured. `JumpInput` remains a native string input.
7
+
8
+ ```tsx
9
+ import { useRef, useState } from 'react'
10
+ import { JumpTokenInput, JumpButton, type JumpTokenInputValue,
11
+ type JumpTokenInputHandle } from '@mario_hahn/jumpy-ui'
12
+
13
+ function MessageEditor() {
14
+ const input = useRef<JumpTokenInputHandle>(null)
15
+ const [value, setValue] = useState<JumpTokenInputValue>([
16
+ { type: 'text', text: 'Hello ' },
17
+ { type: 'token', id: 'name-1', value: 'customer.firstName', label: 'First name' },
18
+ { type: 'text', text: '!' },
19
+ ])
20
+ return <>
21
+ <JumpTokenInput ref={input} label="Message" hint="Insert placeholders"
22
+ value={value} onChange={setValue} placeholder="Write a message" />
23
+ <JumpButton onClick={() => input.current?.insertToken({
24
+ value: 'order.number', label: 'Order number',
25
+ })}>Insert order number</JumpButton>
26
+ <JumpButton onClick={() => setValue([])}>Clear</JumpButton>
27
+ </>
28
+ }
29
+ ```
30
+
31
+ - `value`/`onChange` control the entire structured value. For uncontrolled editing
32
+ use `defaultValue`. Adjacent text parts are merged and empty text parts omitted.
33
+ - Each token instance needs a unique `id`; `value` is its business identifier and
34
+ may repeat. `label` is display text. `insertToken` generates an ID when omitted.
35
+ - Ref methods: `focus()`, `insertToken({ id?, value, label })`, `insertText(text)`,
36
+ and `removeToken(id)`. Insertion replaces the current/last selection, or appends
37
+ if there is none. Opening an external toolbar does not lose the insertion point.
38
+ - Backspace **after** a token or Delete **before** it removes the whole token.
39
+ Backspace before a token deletes the preceding character. Tokens also have a
40
+ remove button. Explicit `onTokenInsert`/`onTokenRemove` callbacks accompany edit
41
+ notifications (including undo/redo); `onChange` remains the state update API.
42
+ - Undo/redo uses Lexical history. External value replacement resets that history.
43
+ - Internal copy/paste preserves tokens and assigns fresh IDs to pasted instances.
44
+ Other applications receive plain labels/text. Plain-text paste is supported;
45
+ arbitrary HTML is not inserted. The field is single-line: pasted line breaks
46
+ become spaces and Enter does not insert a paragraph.
47
+ - `disabled`, `readOnly`, `error`, `status`, `label`, `hint`, `placeholder` and ARIA
48
+ props are supported. Read-only tokens cannot be removed. The ref is an editor
49
+ handle, not an `HTMLInputElement`. Submit the structured value through your form
50
+ state; this is not a native input's string-valued form serialization.
51
+
52
+ Playground: `/?component=token-input`. The component uses Lexical with atomic token
53
+ nodes; there is no manual HTML-to-value parsing and no consumer Tailwind dependency.
54
+
55
+ ## Dropdown popup width
56
+
57
+ The default dropdown popup aligns with the outer visible field and uses its full
58
+ width, including the icon area (but excluding helper text). For longer options:
59
+
60
+ ```tsx
61
+ <JumpDropdown label="Areas" items={items} popupMinWidth={320} />
62
+ ```
63
+
64
+ `popupMinWidth` is an optional minimum in CSS pixels. The popup never shrinks below
65
+ the field width unless viewport space requires it. It is constrained to the
66
+ available viewport and shifted at screen edges. Searching does not change its
67
+ requested width. The prop does not change the field's own width. `inputRef` still
68
+ points to the combobox input, and Escape/single selection restore input focus.
69
+
70
+ ## Field widths
71
+
72
+ Text fields, dropdowns, date pickers and time pickers fill their parent container.
73
+ Constrain the surrounding layout for compact controls, for example with a grid
74
+ column or a wrapper `maxWidth`. Calendar and time popups retain their own sizing;
75
+ they do not expand to match a wide field.
76
+
3
77
  ## Sticky tables and selection
4
78
 
5
79
  `JumpTable stickyHeader` fixes both the header and footer inside the scrollable
6
80
  container. They use `--jumpy-cmp-table-backdrop-color` for a continuous background
7
81
  behind the decorative cell surfaces. The default resolves to the opaque semantic
8
- floating surface in each preset. Keep any custom backdrop override opaque.
82
+ card surface in each preset. Normal cell decorations are transparent; selected
83
+ and hovered cells use their semantic interaction surfaces. The scroll container
84
+ and pinned cells share the same backdrop. Keep any custom backdrop override opaque.
85
+ Use `showHorizontalBorders` for explicit row separators in all columns.
9
86
 
10
87
  `JumpTableCell` and `JumpTableHeaderCell` support `pinned="left"` or `pinned="right"`;
11
88
  use `pinnedEdge` for the edge divider. Pinned cells use the same backdrop as the
@@ -75,7 +152,7 @@ Jumpy Components als ein gemeinsames UI-Paket.
75
152
  Starting with 0.5.0, Jumpy UI uses the public npmjs registry. No package token is required to install:
76
153
 
77
154
  ```bash
78
- npm install @mario_hahn/jumpy-ui@^0.8.0
155
+ npm install @mario_hahn/jumpy-ui@^0.9.0
79
156
  ```
80
157
 
81
158
  The public npm package uses the `@mario_hahn` scope. Older GitHub Packages releases
@@ -22624,6 +22624,10 @@ var providerStyles = `
22624
22624
  transform var(--jumpy-animation-duration-xsmall) var(--jumpy-animation-easing-drift);
22625
22625
  }
22626
22626
 
22627
+ [data-jumpy-theme='true'] [data-jumpy-component='token-input'] > p {
22628
+ margin: 0;
22629
+ }
22630
+
22627
22631
  [data-jumpy-theme='true'] [data-jumpy-component='card'][data-interactive='true'] {
22628
22632
  cursor: pointer;
22629
22633
  --jumpy-cmp-card-checkmark-right: var(--jumpy-spacing-gap-xsmall);
@@ -23744,7 +23748,7 @@ var providerStyles = `
23744
23748
  }
23745
23749
 
23746
23750
  [data-jumpy-theme='true'] [data-jumpy-slot='table-wrapper'] {
23747
- --jumpy-cmp-table-backdrop-color: var(--jumpy-non-interactive-background-default-floating);
23751
+ --jumpy-cmp-table-backdrop-color: var(--jumpy-color-surface-card);
23748
23752
  display: block;
23749
23753
  position: relative;
23750
23754
  width: 100%;
@@ -23756,6 +23760,7 @@ var providerStyles = `
23756
23760
  width: 100%;
23757
23761
  max-width: 100%;
23758
23762
  overflow: auto;
23763
+ background-color: var(--jumpy-cmp-table-backdrop-color);
23759
23764
  }
23760
23765
 
23761
23766
  [data-jumpy-theme='true'] [data-jumpy-slot='table-container'][data-sticky-header='true'] {
@@ -23775,18 +23780,6 @@ var providerStyles = `
23775
23780
  top: 0;
23776
23781
  }
23777
23782
 
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
23783
  [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
23784
  /* Only the decorative surface is rounded; sticky backdrops are rectangular. */
23792
23785
  border-radius: 0;
@@ -23840,7 +23833,7 @@ var providerStyles = `
23840
23833
 
23841
23834
  [data-jumpy-theme='true'] [data-jumpy-component='table-cell'],
23842
23835
  [data-jumpy-theme='true'] [data-jumpy-component='table-header-cell'] {
23843
- --jumpy-cmp-table-cell-surface-color: var(--jumpy-interactive-inactive-regular-default-surface, transparent);
23836
+ --jumpy-cmp-table-cell-surface-color: transparent;
23844
23837
  display: table-cell;
23845
23838
  position: relative;
23846
23839
  height: var(--jumpy-spacing-size-2xlarge);
@@ -23852,7 +23845,7 @@ var providerStyles = `
23852
23845
  }
23853
23846
 
23854
23847
  [data-jumpy-theme='true'] [data-jumpy-component='table-header-cell'] {
23855
- --jumpy-cmp-table-cell-surface-color: color-mix(in srgb, var(--jumpy-color-neutral-ultralight) calc(var(--jumpy-opacity-medium) * 100%), transparent);
23848
+ --jumpy-cmp-table-cell-surface-color: color-mix(in srgb, var(--jumpy-color-surface-field) calc(var(--jumpy-opacity-medium) * 100%), transparent);
23856
23849
  }
23857
23850
 
23858
23851
  [data-jumpy-theme='true'] [data-jumpy-component='table-cell'][data-align='start'],
@@ -23887,9 +23880,10 @@ var providerStyles = `
23887
23880
  [data-jumpy-theme='true'] [data-jumpy-component='table-cell']::before,
23888
23881
  [data-jumpy-theme='true'] [data-jumpy-component='table-header-cell']::before {
23889
23882
  position: absolute;
23883
+ z-index: 1;
23890
23884
  inset-inline: 0;
23891
23885
  bottom: 0;
23892
- background-color: var(--jumpy-color-neutral-ultralight, var(--jumpy-color-border-subtle));
23886
+ background-color: var(--jumpy-color-border-subtle);
23893
23887
  height: var(--jumpy-spacing-outline-small);
23894
23888
  content: '';
23895
23889
  }
@@ -24139,31 +24133,17 @@ var providerStyles = `
24139
24133
 
24140
24134
  [data-jumpy-theme='true'] [data-jumpy-component='table-footer'] {
24141
24135
  position: relative;
24142
- background-color: var(--jumpy-interactive-inactive-regular-default-surface);
24143
- }
24144
-
24145
- [data-jumpy-theme='true'] [data-jumpy-component='table-footer']::before,
24146
- [data-jumpy-theme='true'] [data-jumpy-component='table-footer']::after {
24147
- position: absolute;
24148
- right: 0;
24149
- left: 0;
24150
- z-index: 1;
24151
- background-color: var(--jumpy-interactive-inactive-regular-default-border);
24152
- height: var(--jumpy-spacing-outline-small);
24153
- content: '';
24136
+ background-color: var(--jumpy-cmp-table-backdrop-color);
24154
24137
  }
24155
24138
 
24156
- [data-jumpy-theme='true'] [data-jumpy-component='table-footer']::before {
24157
- top: 0;
24139
+ /* Native cell borders paint consistently on either side of pinned boundaries.
24140
+ A section pseudo-element would be covered only by the sticky cells. */
24141
+ [data-jumpy-theme='true'] [data-jumpy-component='table-footer'] > [data-jumpy-component='table-row']:first-child > :is([data-jumpy-component='table-cell'], [data-jumpy-component='table-header-cell']) {
24142
+ border-top: var(--jumpy-spacing-outline-small) solid var(--jumpy-color-border-subtle);
24158
24143
  }
24159
24144
 
24160
- [data-jumpy-theme='true'] [data-jumpy-component='table-footer']::after {
24161
- display: none;
24162
- bottom: 0;
24163
- }
24164
-
24165
- [data-jumpy-theme='true'] [data-jumpy-component='table'][data-horizontal-borders='true'] [data-jumpy-component='table-footer']::after {
24166
- display: block;
24145
+ [data-jumpy-theme='true'] [data-jumpy-component='table'][data-horizontal-borders='true'] > [data-jumpy-component='table-footer'] > [data-jumpy-component='table-row']:last-child > :is([data-jumpy-component='table-cell'], [data-jumpy-component='table-header-cell']) {
24146
+ border-bottom: var(--jumpy-spacing-outline-small) solid var(--jumpy-color-border-subtle);
24167
24147
  }
24168
24148
 
24169
24149
  [data-jumpy-theme='true'] [data-jumpy-component='table-footer'] [data-jumpy-component='table-cell']::before {