@marianmeres/stuic 3.168.0 → 3.170.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.
Files changed (31) hide show
  1. package/AGENTS.md +2 -2
  2. package/dist/README.md +1 -1
  3. package/dist/components/Input/FieldOptions.svelte +89 -54
  4. package/dist/components/Input/FieldOptions.svelte.d.ts +13 -0
  5. package/dist/components/Input/README.md +144 -31
  6. package/dist/components/Input/_internal/FieldLikeChips.svelte +286 -0
  7. package/dist/components/Input/_internal/FieldLikeChips.svelte.d.ts +65 -0
  8. package/dist/components/Input/field-options-i18n-sk.d.ts +21 -0
  9. package/dist/components/Input/field-options-i18n-sk.js +61 -0
  10. package/dist/components/Input/field-options-i18n.d.ts +82 -0
  11. package/dist/components/Input/field-options-i18n.js +90 -0
  12. package/dist/components/Input/index.css +58 -0
  13. package/dist/components/Input/index.d.ts +2 -0
  14. package/dist/components/Input/index.js +2 -0
  15. package/dist/components/Pill/Pill.svelte +8 -2
  16. package/dist/components/Pill/Pill.svelte.d.ts +2 -0
  17. package/dist/components/Pill/README.md +35 -22
  18. package/dist/components/Pill/index.css +57 -18
  19. package/dist/components/Timeline/README.md +204 -0
  20. package/dist/components/Timeline/Timeline.svelte +246 -0
  21. package/dist/components/Timeline/Timeline.svelte.d.ts +87 -0
  22. package/dist/components/Timeline/index.css +311 -0
  23. package/dist/components/Timeline/index.d.ts +1 -0
  24. package/dist/components/Timeline/index.js +1 -0
  25. package/dist/index.css +1 -0
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.js +1 -0
  28. package/docs/domains/components.md +39 -1
  29. package/docs/maybe-todo.md +37 -13
  30. package/docs/upgrading.md +6 -0
  31. package/package.json +1 -1
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- 73 Svelte 5 component directories with consistent API patterns. All use runes-based reactivity.
5
+ 74 Svelte 5 component directories with consistent API patterns. All use runes-based reactivity.
6
6
 
7
7
  ## Component Categories
8
8
 
@@ -100,6 +100,7 @@
100
100
  | Thc | Flexible renderer for text, HTML, components, or snippets |
101
101
  | Card | Flexible card with image, title, footer; vertical/horizontal layout |
102
102
  | Stat | KPI/stat card: label + value + delta with trend arrow and semantic coloring |
103
+ | Timeline | Vertical event list on a rail: dot/icon/custom markers, inline or opposite time, alternate layout |
103
104
  | TrendChart | Svelte wrapper for `@marianmeres/trend-chart` (subpath-only: `@marianmeres/stuic/trend-chart`) |
104
105
  | Tree | Hierarchical tree view with keyboard nav and drag-and-drop |
105
106
  | X | Styled close/multiply SVG icon |
@@ -1091,6 +1092,43 @@ Prefix: `--stuic-stepper-*`
1091
1092
 
1092
1093
  ---
1093
1094
 
1095
+ ## Timeline
1096
+
1097
+ Vertical event list with markers on a rail — activity feeds, audit logs, order tracking, history pages. A real `<ol>` (explicit `role="list"`); every item has a marker (small dot, icon bubble when `item.icon` is set, or anything via `renderMarker`), an optional time label, title, description and footer. Data-driven (`items`), static by design — no "current" step (use `Stepper` vertical for progress flows). The list is a CSS grid with `subgrid` items, so the rail and the optional time column align across items without fixed widths; the rail line runs behind the markers and a background-colored ring separates them.
1098
+
1099
+ ### Exports
1100
+
1101
+ | Export | Kind | Description |
1102
+ | ---------------------- | --------- | ------------------------------------------------------------------- |
1103
+ | `Timeline` | component | Main component |
1104
+ | `TimelineProps` | type | Props type |
1105
+ | `TimelineItem` | type | `{ title?, description?, time?, datetime?, icon?, intent?, href? }` |
1106
+ | `TimelineAlign` | type | `"start" \| "alternate"` |
1107
+ | `TimelineTimePosition` | type | `"inline" \| "opposite"` |
1108
+ | `TimelineMarkerKind` | type | `"dot" \| "icon" \| "custom"` (the marker's `data-marker`) |
1109
+ | `TimelineSnippetArg` | type | `{ item, index }` — argument of all three snippets |
1110
+
1111
+ ### Key Props
1112
+
1113
+ | Prop | Type | Default | Description |
1114
+ | -------------- | ------------------------- | ---------- | ----------------------------------------------------------------------------- |
1115
+ | `items` | `TimelineItem[]` | required | The events, in display order (title/description/time/icon are THC) |
1116
+ | `align` | `"start" \| "alternate"` | `"start"` | Rail on the start side, or centered rail with content alternating sides |
1117
+ | `timePosition` | `"inline" \| "opposite"` | `"inline"` | Time above the title inside the content, or in its own column across the rail |
1118
+ | `formatTime` | `(datetime, item) => THC` | — | Fallback label for items with `datetime` but no `time` |
1119
+
1120
+ `item.datetime` (string or `Date`, serialized to ISO) renders the label as `<time datetime>`; without it the label is a `<span>`. `item.intent` (`IntentColorKey`) fills the dot / soft-tints the bubble. `item.href` renders the title as a link.
1121
+
1122
+ Snippets (all receive `{ item, index }`): `renderMarker` (replaces every marker, `data-marker="custom"`), `renderItem` (replaces the whole content cell), `renderFooter` (per-item area under the description). Class slots: `class`, `classItem`, `classMarker`, `classContent`, `classTime`, `classTitle`, `classDescription`, `classFooter`. Markers are `aria-hidden`.
1123
+
1124
+ ### CSS Tokens
1125
+
1126
+ Prefix: `--stuic-timeline-*`
1127
+
1128
+ `gap`, `gap-vertical`, `line-height`, `connector-thickness`, `connector-bg`, `marker-size`, `marker-bg`, `marker-size-icon`, `marker-bg-icon`, `marker-text-icon`, `marker-icon-size`, `marker-radius`, `marker-ring-width`, `marker-ring-color`, `time-font-size`, `time-text`, `title-font-size`, `title-font-weight`, `title-text`, `description-font-size`, `description-text`, `description-margin-top`, `footer-gap`, `footer-margin-top`
1129
+
1130
+ ---
1131
+
1094
1132
  ## CronInput
1095
1133
 
1096
1134
  Cron expression editor with preset selector, manual 5-field editor, raw expression input, human-readable descriptions, and next-run calculation.
@@ -18,7 +18,8 @@ Checked first, to avoid false positives:
18
18
  - **Table pagination** — built into `DataTable` (`showpager`)
19
19
  - **Multi-select / tags input** — `FieldOptions` (async `getOptions` search, typeahead,
20
20
  `cardinality`, option groups, `allowUnknown` for ad-hoc values, `ordered` for manual
21
- arrangement). See the note at the bottom on the inline-chip presentation variant.
21
+ arrangement, `chips` for the inline tag form factor). See the note at the bottom on
22
+ the inline-chip presentation.
22
23
  - **File dropzone** — `actions/file-dropzone` + `FieldFile` / `FieldAssets`
23
24
 
24
25
  ## Tier 1 — staples nearly every comparable library ships
@@ -58,8 +59,11 @@ Checked first, to avoid false positives:
58
59
  `WithSidePanel`, and `persistent-state` already provide the pieces.
59
60
  9. **Range slider (dual-thumb)** — `Slider` is deliberately single-value; a min/max
60
61
  range variant (price filters etc.) is a recurring ask.
61
- 10. **Timeline / activity feed** — vertical event list with markers; common in
62
- admin/audit views.
62
+ 10. ~~**Timeline / activity feed**~~ — ✅ shipped (see `src/lib/components/Timeline/`):
63
+ vertical event list on a rail with dot / icon-bubble / custom (snippet) markers,
64
+ per-item intent, `<time datetime>` support with an optional formatter, inline or
65
+ opposite time column, `start` / `alternate` alignment; `subgrid` keeps the columns
66
+ aligned without fixed widths.
63
67
  11. ~~**Stat / KPI card**~~ — ✅ shipped (see `src/lib/components/Stat/`): label +
64
68
  value + delta with trend arrow and semantic coloring (`trendIntent` for
65
69
  down-is-good metrics), hint, corner icon, footer/sparkline area.
@@ -82,16 +86,36 @@ Checked first, to avoid false positives:
82
86
  ## Note: inline-chip presentation of FieldOptions
83
87
 
84
88
  Initially listed as a Tier-1 "tags input" gap; retracted — `FieldOptions` covers the
85
- capability. What stuic lacks is at most the _inline chip form factor_: chips inside the
86
- field with per-chip remove ×, a text input riding alongside, suggestions in a popover
87
- without leaving the page. Faster for dense desktop/admin work; the existing modal flow
88
- is arguably better on mobile.
89
-
90
- If ever built, the design to argue for: a presentation mode of `FieldOptions` (the
91
- selection model — `ItemCollection`, `cardinality`, `allowUnknown` — is already there),
92
- not a new component. Inline combobox on pointer devices, delegating to the existing
93
- modal on touch/small screens (`breakpoint.svelte.ts` + `device-pointer.svelte.ts`
94
- enable the switch).
89
+ capability. What stuic lacked was the _inline chip form factor_. That splits into two
90
+ separable halves, and only the second one has a mobile problem:
91
+
92
+ 1. ~~**Chips as the field's display**~~ — ✅ shipped (`FieldOptions` `chips` prop, see
93
+ `Input/README.md`): the closed field shows the selection as removable `Pill` chips
94
+ (per-chip ×, focus kept in the field, `change` dispatched so validation re-runs) plus a
95
+ trailing button that opens the existing modal; the empty part of the row opens it too.
96
+ Internally a `FieldLikeButton` sibling (`Input/_internal/FieldLikeChips.svelte`) — the
97
+ chips carry their own buttons, so they cannot live inside the `<button>` trigger. Works
98
+ on every device; the one touch concern (× target size) is handled with a padded hit
99
+ area on `pointer: coarse`.
100
+ 2. **Inline adding** (type into the field, suggestions, Enter commits) — not built. This is
101
+ where every mobile hazard lives (see the reality check below). The design to argue for,
102
+ if ever built:
103
+ - a presentation mode of `FieldOptions`, not a new component — the selection model
104
+ (`ItemCollection`, `cardinality`, `allowUnknown`, `ordered`) is already there. But the
105
+ engine is currently bound to the modal lifecycle (hydrate on open, fetch while
106
+ visible, clear on submit) and would need extracting into a shared `.svelte.ts` class
107
+ rather than more branches in the 1250-line file; that is the real cost
108
+ - no floating listbox popover: reuse the existing `typeahead` action (ghost text, Tab
109
+ accepts, Enter commits, Backspace at position 0 removes the last chip via
110
+ `onDeleteRequest`). No anchored dropdown means the soft-keyboard hazard disappears by
111
+ construction; the modal stays the browse path via the trailing button. A real list
112
+ popover can be added later behind the same prop if ghost text proves insufficient
113
+ - gate it on the `md` breakpoint (`breakpoint.svelte.ts`), not on `DevicePointer` —
114
+ that util uses `any-pointer`, so a touchscreen laptop counts as coarse and an iPad
115
+ with a trackpad as fine; the breakpoint is deterministic and testable in the browser
116
+ suite. If pointer detection is wanted as well, it should be the primary
117
+ `pointer: coarse`
118
+ - below the breakpoint, delegate to the modal — i.e. exactly the shipped `chips` mode
95
119
 
96
120
  Mobile reality check for the inline variant, if it were ever made touch-capable
97
121
  instead of delegating:
package/docs/upgrading.md CHANGED
@@ -99,6 +99,12 @@ interface InputWrapClassProps {
99
99
 
100
100
  Previously most fields only accepted 5–7 of these. You can now pass any of them to **FieldInput, FieldTextarea, FieldSelect, FieldSwitch, FieldFile, FieldLikeButton, FieldObject, FieldOptions, FieldAssets, FieldPhoneNumber, FieldInputLocalized, FieldKeyValues** uniformly. `FieldCheckbox` and `FieldRadios` use bespoke layouts and keep their own narrower class-prop surface.
101
101
 
102
+ ### FieldOptions
103
+
104
+ `chips` prop (opt-in): the closed field shows the selection as inline, removable `Pill` chips plus a trailing button that opens the usual modal. Removing a chip writes `value` and fires `onChange` without the modal. Companion props `classChip` / `chipIntent`; `renderValue` is ignored in this mode. The default rendering is unchanged.
105
+
106
+ `Pill` gained `dismissLabel` — the accessible name of its × button (default `"Dismiss"`).
107
+
102
108
  ### Checkout
103
109
 
104
110
  New util:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/stuic",
3
- "version": "3.168.0",
3
+ "version": "3.170.0",
4
4
  "packageManager": "pnpm@11.5.0",
5
5
  "scripts": {
6
6
  "dev": "vite dev",