@onereach/idw-ui-components 0.1.2-beta.7.0 → 0.2.0-beta.27.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 (143) hide show
  1. package/README.md +360 -1
  2. package/dist/cjs/index.js +2 -18
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/esm/index.js +1639 -2
  5. package/dist/esm/index.js.map +1 -1
  6. package/dist/idw-ui-components.css +1 -0
  7. package/dist/types/components/Feeds/FeedEmbed/FeedEmbed.vue.d.ts +16 -0
  8. package/dist/types/components/Feeds/FeedEmbed/FeedEmbed.vue.d.ts.map +1 -0
  9. package/dist/types/components/Feeds/FeedFileContent/FeedFileContent.vue.d.ts +6 -0
  10. package/dist/types/components/Feeds/FeedFileContent/FeedFileContent.vue.d.ts.map +1 -0
  11. package/dist/types/components/Feeds/FeedFileContent/index.d.ts +3 -0
  12. package/dist/types/components/Feeds/FeedFileContent/index.d.ts.map +1 -0
  13. package/dist/types/components/Feeds/FeedFileContent/types.d.ts +13 -0
  14. package/dist/types/components/Feeds/FeedFileContent/types.d.ts.map +1 -0
  15. package/dist/types/components/Feeds/FeedHtmlContent/FeedHtmlContent.vue.d.ts +6 -0
  16. package/dist/types/components/Feeds/FeedHtmlContent/FeedHtmlContent.vue.d.ts.map +1 -0
  17. package/dist/types/components/Feeds/FeedHtmlContent/index.d.ts +3 -0
  18. package/dist/types/components/Feeds/FeedHtmlContent/index.d.ts.map +1 -0
  19. package/dist/types/components/Feeds/FeedHtmlContent/types.d.ts +13 -0
  20. package/dist/types/components/Feeds/FeedHtmlContent/types.d.ts.map +1 -0
  21. package/dist/types/components/Feeds/FeedItemBase/FeedItemBase.vue.d.ts +42 -0
  22. package/dist/types/components/Feeds/FeedItemBase/FeedItemBase.vue.d.ts.map +1 -0
  23. package/dist/types/components/Feeds/FeedItemBase/index.d.ts +3 -0
  24. package/dist/types/components/Feeds/FeedItemBase/index.d.ts.map +1 -0
  25. package/dist/types/components/Feeds/FeedItemBase/types.d.ts +35 -0
  26. package/dist/types/components/Feeds/FeedItemBase/types.d.ts.map +1 -0
  27. package/dist/types/components/Feeds/FeedItemMetaFooter/FeedItemMetaFooter.vue.d.ts +12 -0
  28. package/dist/types/components/Feeds/FeedItemMetaFooter/FeedItemMetaFooter.vue.d.ts.map +1 -0
  29. package/dist/types/components/Feeds/FeedItemMetaFooter/index.d.ts +3 -0
  30. package/dist/types/components/Feeds/FeedItemMetaFooter/index.d.ts.map +1 -0
  31. package/dist/types/components/Feeds/FeedItemMetaFooter/types.d.ts +27 -0
  32. package/dist/types/components/Feeds/FeedItemMetaFooter/types.d.ts.map +1 -0
  33. package/dist/types/components/Feeds/FeedList/FeedList.vue.d.ts +60 -0
  34. package/dist/types/components/Feeds/FeedList/FeedList.vue.d.ts.map +1 -0
  35. package/dist/types/components/Feeds/FeedList/FeedListItemBody.vue.d.ts +17 -0
  36. package/dist/types/components/Feeds/FeedList/FeedListItemBody.vue.d.ts.map +1 -0
  37. package/dist/types/components/Feeds/FeedList/index.d.ts +3 -0
  38. package/dist/types/components/Feeds/FeedList/index.d.ts.map +1 -0
  39. package/dist/types/components/Feeds/FeedList/types.d.ts +69 -0
  40. package/dist/types/components/Feeds/FeedList/types.d.ts.map +1 -0
  41. package/dist/types/components/Feeds/FeedMarkdownContent/FeedMarkdownContent.vue.d.ts +7 -0
  42. package/dist/types/components/Feeds/FeedMarkdownContent/FeedMarkdownContent.vue.d.ts.map +1 -0
  43. package/dist/types/components/Feeds/FeedMarkdownContent/index.d.ts +3 -0
  44. package/dist/types/components/Feeds/FeedMarkdownContent/index.d.ts.map +1 -0
  45. package/dist/types/components/Feeds/FeedMarkdownContent/types.d.ts +12 -0
  46. package/dist/types/components/Feeds/FeedMarkdownContent/types.d.ts.map +1 -0
  47. package/dist/types/components/Feeds/FeedSkillContent/FeedSkillContent.vue.d.ts +29 -0
  48. package/dist/types/components/Feeds/FeedSkillContent/FeedSkillContent.vue.d.ts.map +1 -0
  49. package/dist/types/components/Feeds/FeedSkillContent/index.d.ts +3 -0
  50. package/dist/types/components/Feeds/FeedSkillContent/index.d.ts.map +1 -0
  51. package/dist/types/components/Feeds/FeedSkillContent/types.d.ts +29 -0
  52. package/dist/types/components/Feeds/FeedSkillContent/types.d.ts.map +1 -0
  53. package/dist/types/components/Feeds/feedEmbed.d.ts +10 -0
  54. package/dist/types/components/Feeds/feedEmbed.d.ts.map +1 -0
  55. package/dist/types/components/Feeds/formatFeedReadingTime.d.ts +3 -0
  56. package/dist/types/components/Feeds/formatFeedReadingTime.d.ts.map +1 -0
  57. package/dist/types/components/Feeds/index.d.ts +10 -0
  58. package/dist/types/components/Feeds/index.d.ts.map +1 -0
  59. package/dist/types/components/SkillCard/SkillCard.vue.d.ts +20 -0
  60. package/dist/types/components/SkillCard/SkillCard.vue.d.ts.map +1 -0
  61. package/dist/types/components/SkillCard/index.d.ts +4 -0
  62. package/dist/types/components/SkillCard/index.d.ts.map +1 -0
  63. package/dist/types/components/SkillCard/types.d.ts +17 -0
  64. package/dist/types/components/SkillCard/types.d.ts.map +1 -0
  65. package/dist/types/idw-card/bind/bindIdwCard.d.ts +7 -0
  66. package/dist/types/idw-card/bind/bindIdwCard.d.ts.map +1 -0
  67. package/dist/types/idw-card/bind/index.d.ts +2 -0
  68. package/dist/types/idw-card/bind/index.d.ts.map +1 -0
  69. package/dist/types/idw-card/form/dates.d.ts +5 -0
  70. package/dist/types/idw-card/form/dates.d.ts.map +1 -0
  71. package/dist/types/idw-card/form/formContext.d.ts +10 -0
  72. package/dist/types/idw-card/form/formContext.d.ts.map +1 -0
  73. package/dist/types/idw-card/form/index.d.ts +3 -0
  74. package/dist/types/idw-card/form/index.d.ts.map +1 -0
  75. package/dist/types/idw-card/host/hostConfig.d.ts +13 -0
  76. package/dist/types/idw-card/host/hostConfig.d.ts.map +1 -0
  77. package/dist/types/idw-card/host/index.d.ts +3 -0
  78. package/dist/types/idw-card/host/index.d.ts.map +1 -0
  79. package/dist/types/idw-card/index.d.ts +10 -0
  80. package/dist/types/idw-card/index.d.ts.map +1 -0
  81. package/dist/types/idw-card/renderer/CardRenderer.vue.d.ts +18 -0
  82. package/dist/types/idw-card/renderer/CardRenderer.vue.d.ts.map +1 -0
  83. package/dist/types/idw-card/renderer/IdwCardActionBar.vue.d.ts +12 -0
  84. package/dist/types/idw-card/renderer/IdwCardActionBar.vue.d.ts.map +1 -0
  85. package/dist/types/idw-card/renderer/IdwCardElementView.vue.d.ts +16 -0
  86. package/dist/types/idw-card/renderer/IdwCardElementView.vue.d.ts.map +1 -0
  87. package/dist/types/idw-card/renderer/actionStyle.d.ts +12 -0
  88. package/dist/types/idw-card/renderer/actionStyle.d.ts.map +1 -0
  89. package/dist/types/idw-card/renderer/elements/ActionSetElement.vue.d.ts +12 -0
  90. package/dist/types/idw-card/renderer/elements/ActionSetElement.vue.d.ts.map +1 -0
  91. package/dist/types/idw-card/renderer/elements/BadgeElement.vue.d.ts +7 -0
  92. package/dist/types/idw-card/renderer/elements/BadgeElement.vue.d.ts.map +1 -0
  93. package/dist/types/idw-card/renderer/elements/ColumnSetElement.vue.d.ts +16 -0
  94. package/dist/types/idw-card/renderer/elements/ColumnSetElement.vue.d.ts.map +1 -0
  95. package/dist/types/idw-card/renderer/elements/ContainerElement.vue.d.ts +16 -0
  96. package/dist/types/idw-card/renderer/elements/ContainerElement.vue.d.ts.map +1 -0
  97. package/dist/types/idw-card/renderer/elements/FactSetElement.vue.d.ts +7 -0
  98. package/dist/types/idw-card/renderer/elements/FactSetElement.vue.d.ts.map +1 -0
  99. package/dist/types/idw-card/renderer/elements/FileElement.vue.d.ts +9 -0
  100. package/dist/types/idw-card/renderer/elements/FileElement.vue.d.ts.map +1 -0
  101. package/dist/types/idw-card/renderer/elements/HtmlElement.vue.d.ts +9 -0
  102. package/dist/types/idw-card/renderer/elements/HtmlElement.vue.d.ts.map +1 -0
  103. package/dist/types/idw-card/renderer/elements/IconElement.vue.d.ts +7 -0
  104. package/dist/types/idw-card/renderer/elements/IconElement.vue.d.ts.map +1 -0
  105. package/dist/types/idw-card/renderer/elements/ImageElement.vue.d.ts +7 -0
  106. package/dist/types/idw-card/renderer/elements/ImageElement.vue.d.ts.map +1 -0
  107. package/dist/types/idw-card/renderer/elements/ImageSetElement.vue.d.ts +7 -0
  108. package/dist/types/idw-card/renderer/elements/ImageSetElement.vue.d.ts.map +1 -0
  109. package/dist/types/idw-card/renderer/elements/InputElement.vue.d.ts +7 -0
  110. package/dist/types/idw-card/renderer/elements/InputElement.vue.d.ts.map +1 -0
  111. package/dist/types/idw-card/renderer/elements/MediaElement.vue.d.ts +7 -0
  112. package/dist/types/idw-card/renderer/elements/MediaElement.vue.d.ts.map +1 -0
  113. package/dist/types/idw-card/renderer/elements/ProgressElement.vue.d.ts +7 -0
  114. package/dist/types/idw-card/renderer/elements/ProgressElement.vue.d.ts.map +1 -0
  115. package/dist/types/idw-card/renderer/elements/SkillElement.vue.d.ts +14 -0
  116. package/dist/types/idw-card/renderer/elements/SkillElement.vue.d.ts.map +1 -0
  117. package/dist/types/idw-card/renderer/elements/TableElement.vue.d.ts +7 -0
  118. package/dist/types/idw-card/renderer/elements/TableElement.vue.d.ts.map +1 -0
  119. package/dist/types/idw-card/renderer/elements/TextElement.vue.d.ts +7 -0
  120. package/dist/types/idw-card/renderer/elements/TextElement.vue.d.ts.map +1 -0
  121. package/dist/types/idw-card/renderer/index.d.ts +3 -0
  122. package/dist/types/idw-card/renderer/index.d.ts.map +1 -0
  123. package/dist/types/idw-card/renderer/types.d.ts +12 -0
  124. package/dist/types/idw-card/renderer/types.d.ts.map +1 -0
  125. package/dist/types/idw-card/schema/index.d.ts +3 -0
  126. package/dist/types/idw-card/schema/index.d.ts.map +1 -0
  127. package/dist/types/idw-card/templates/approval.d.ts +94 -0
  128. package/dist/types/idw-card/templates/approval.d.ts.map +1 -0
  129. package/dist/types/idw-card/templates/compile.d.ts +7 -0
  130. package/dist/types/idw-card/templates/compile.d.ts.map +1 -0
  131. package/dist/types/idw-card/templates/index.d.ts +7 -0
  132. package/dist/types/idw-card/templates/index.d.ts.map +1 -0
  133. package/dist/types/idw-card/templates/registry.d.ts +16 -0
  134. package/dist/types/idw-card/templates/registry.d.ts.map +1 -0
  135. package/dist/types/idw-card/templates/types.d.ts +20 -0
  136. package/dist/types/idw-card/templates/types.d.ts.map +1 -0
  137. package/dist/types/index.d.ts +3 -0
  138. package/dist/types/index.d.ts.map +1 -1
  139. package/package.json +33 -14
  140. package/dist/cjs/format-idw-summary.js +0 -11
  141. package/dist/cjs/format-idw-summary.js.map +0 -1
  142. package/dist/esm/format-idw-summary.js +0 -8
  143. package/dist/esm/format-idw-summary.js.map +0 -1
package/README.md CHANGED
@@ -2,13 +2,21 @@
2
2
 
3
3
  > Shared IDW UI components and browser helpers. Consumed by `idw-ui`.
4
4
 
5
+ Peer dependencies:
6
+
7
+ - `vue` ^3.5
8
+ - `@onereach/ui-components` >= 26.14
9
+ - `@onereach/idw-markdown-renderer` >= 1.1 (used by `FeedMarkdownContent` / `FeedSkillContent`)
10
+
11
+ The host app must load Onereach styles / Tailwind (`@onereach/styles`) so utility classes and design tokens resolve. Include this package in the host Tailwind `content` globs (for example `./node_modules/@onereach/idw-ui-components/dist/**/*.{js,mjs,cjs}`) so class names used by components are not purged.
12
+
5
13
  ## Installation
6
14
 
7
15
  ```bash
8
16
  pnpm add @onereach/idw-ui-components
9
17
  ```
10
18
 
11
- ## Usage
19
+ ## Helpers
12
20
 
13
21
  ```typescript
14
22
  import { formatIdwSummary } from '@onereach/idw-ui-components';
@@ -16,3 +24,354 @@ import type { IdwSummary } from '@onereach/idw-contracts';
16
24
 
17
25
  const label = formatIdwSummary(summary satisfies IdwSummary);
18
26
  ```
27
+
28
+ ## SkillCard
29
+
30
+ Presentational skill tile (sizes `xs` / `s` / `l`). Used by feeds and settings surfaces.
31
+
32
+ ```vue
33
+ <script setup lang="ts">
34
+ import { CardSize, SkillCard, type SkillCardData } from '@onereach/idw-ui-components';
35
+
36
+ const skill = {
37
+ id: '1',
38
+ name: 'Vacation',
39
+ image: '/skill.png',
40
+ domain: 'HR',
41
+ } satisfies SkillCardData;
42
+ </script>
43
+
44
+ <template>
45
+ <SkillCard
46
+ :skill="skill"
47
+ :size="CardSize.S"
48
+ @click="onOpen"
49
+ />
50
+ </template>
51
+ ```
52
+
53
+ ## FeedItemBase
54
+
55
+ Presentational shell for schema-driven feed items. It owns metadata, title, short description, feed-level controls, and expand/collapse. Body content is opaque via slots.
56
+
57
+ ```vue
58
+ <script setup lang="ts">
59
+ import { FeedItemBase } from '@onereach/idw-ui-components';
60
+ </script>
61
+
62
+ <template>
63
+ <FeedItemBase
64
+ id="feed-1"
65
+ title="Important meeting needs review"
66
+ short-content="Owner Strategy Review overlaps with your vacation."
67
+ timestamp="1 min ago"
68
+ timestamp-datetime="2026-08-07T12:00:00.000Z"
69
+ source="by Vacation Skill"
70
+ >
71
+ <template #body>
72
+ <!-- Markdown, HTML, skill body, or embedded app -->
73
+ </template>
74
+
75
+ <template #actions>
76
+ <!-- Domain actions such as Approve or Reschedule -->
77
+ </template>
78
+
79
+ <template #footer>
80
+ <!-- Optional feedback, comments, or additional context (shown while body is open) -->
81
+ </template>
82
+ </FeedItemBase>
83
+ </template>
84
+ ```
85
+
86
+ ### Props
87
+
88
+ | Prop | Type | Default | Description |
89
+ |------|------|---------|-------------|
90
+ | `id` | `string` | — | Stable feed item id (used for a11y ids) |
91
+ | `title` | `string` | — | Shell title (always visible) |
92
+ | `shortContent` | `string` | — | Shell short description |
93
+ | `timestamp` | `string` | — | Preformatted timestamp text |
94
+ | `timestampDatetime` | `string` | — | Optional value for `<time datetime>` |
95
+ | `source` | `string` | — | Source / author text |
96
+ | `expandable` | `boolean` | `true` | Whether the expand control is shown |
97
+ | `fullscreenControl` | `boolean` | `false` | Shows `open_in_full` inside default `#controls`; host owns overlay via `fullscreen` |
98
+ | `mentionControl` | `boolean` | `true` | Shows `alternate_email` (mention) inside default `#controls` |
99
+ | `isNew` | `boolean` | `false` | Attention shell (`primary-opacity-12`) vs settled shell (`surface-2`) |
100
+ | `controlLabels` | `Partial<Record<FeedItemControl, string>> & { fullscreen?: string }` | Mention / Fullscreen | Optional localized tooltips |
101
+
102
+ When `expandable` is `false`, the body is always shown and the expand button is hidden.
103
+
104
+ Expand labels are fixed (`Show more` / `Show less`). The scrollable body uses `max-height: 37.875rem` by default.
105
+
106
+ `FeedItemControl`: `'mention'`
107
+
108
+ ### Slots
109
+
110
+ - `body` — rich / schema / app content (lazy-mounted on first expand, kept mounted while the item lives)
111
+ - `actions` — domain action buttons (visible only while body is open; empty slot content is hidden)
112
+ - `footer` — optional extra footer (visible only while body is open)
113
+ - `controls` — override default controls entirely (including fullscreen when `fullscreenControl` is true)
114
+
115
+ ### Default controls
116
+
117
+ The default `#controls` content includes mention (`alternate_email`) when `mentionControl` is true (default), and fullscreen when `fullscreenControl` is true. A custom `#controls` slot replaces both.
118
+
119
+ ```vue
120
+ <!-- Localize built-in control tooltips -->
121
+ <FeedItemBase
122
+ ...
123
+ :control-labels="{ mention: 'Згадати', fullscreen: 'На весь екран' }"
124
+ />
125
+ ```
126
+
127
+ ### Events
128
+
129
+ - `update:expanded` — expanded state changed
130
+ - `expand` / `collapse` — convenience events
131
+ - `control-click` — `'mention'` from the default mention control
132
+ - `fullscreen` — fullscreen control clicked; host should open its overlay (modal / route)
133
+
134
+ ### Body lifecycle
135
+
136
+ The body slot mounts on the first expansion and stays mounted afterwards. Collapsing hides it with `v-show` so embedded apps / iframes are not destroyed automatically.
137
+
138
+ ## Feed type content (body slot)
139
+
140
+ Four presentational bodies for feed types (`markdown` | `skill` | `html` | `file`). Use them inside `FeedItemBase` `#body`. `FeedMarkdownContent` / `FeedSkillContent` encapsulate `@onereach/idw-markdown-renderer` plus feed `styled-content` typography. `FeedSkillContent` renders the built-in `SkillCard` when `skill` is passed (optional `#skill` override remains for rare custom cards).
141
+
142
+ ```vue
143
+ <script setup lang="ts">
144
+ import {
145
+ FeedItemBase,
146
+ FeedMarkdownContent,
147
+ FeedSkillContent,
148
+ FeedHtmlContent,
149
+ FeedFileContent,
150
+ type SkillCardData,
151
+ } from '@onereach/idw-ui-components';
152
+
153
+ const skill = { id: '1', name: 'Vacation', image: '/s.png', domain: 'HR' } satisfies SkillCardData;
154
+ </script>
155
+
156
+ <template>
157
+ <FeedItemBase id="1" title="Markdown" short-content="…">
158
+ <template #body>
159
+ <FeedMarkdownContent :text="content" />
160
+ </template>
161
+ </FeedItemBase>
162
+
163
+ <FeedItemBase id="2" title="Skill" short-content="…">
164
+ <template #body>
165
+ <FeedSkillContent
166
+ :text="content"
167
+ :skill="skill"
168
+ start-skill-label="Open Skill"
169
+ @start-skill="onStartSkill"
170
+ @skill-click="onSkillClick"
171
+ />
172
+ </template>
173
+ </FeedItemBase>
174
+
175
+ <FeedItemBase id="3" title="HTML" :fullscreen-control="true" class="[&_.feed-item-base__body]:!max-h-none">
176
+ <template #body>
177
+ <FeedHtmlContent title="HTML" :content="html" />
178
+ </template>
179
+ </FeedItemBase>
180
+
181
+ <FeedItemBase id="4" title="File" :fullscreen-control="true" class="[&_.feed-item-base__body]:!max-h-none">
182
+ <template #body>
183
+ <FeedFileContent title="File" :src="fileUrl" />
184
+ </template>
185
+ </FeedItemBase>
186
+ </template>
187
+ ```
188
+
189
+ | Component | Feed type | Notes |
190
+ |-----------|-----------|--------|
191
+ | `FeedMarkdownContent` | `markdown` | Renders `text` via `OrWebMarkdownRender` + `styled-content` / body typography |
192
+ | `FeedSkillContent` | `skill` | Built-in `SkillCard` via `skill` prop + markdown; optional `startSkillLabel` → `start-skill`; `skill-click` |
193
+ | `FeedHtmlContent` | `html` | `srcdoc` iframe using the fixed `FEED_EMBED_SANDBOX`; `size`: `'list'` \| `'fill'` |
194
+ | `FeedFileContent` | `file` | `src` iframe using the fixed `FEED_EMBED_SANDBOX`; same `size` prop |
195
+
196
+ Shared helpers: `FEED_EMBED_SANDBOX`, `FEED_EMBED_SIZE_CLASS`, type `FeedEmbedSize`. The sandbox value is not configurable through component props. Html/file share an internal embed implementation; empty `src` / `srcdoc` renders nothing.
197
+
198
+ ## FeedList
199
+
200
+ Scrollable list of discriminated `FeedListItem` rows. Each row is a `FeedItemBase` shell with the matching type body. Host owns data fetching, i18n, fullscreen modal, and list footer content (e.g. reactions / comments). Skill cards are rendered inside the toolkit when `item.skill` is set.
201
+
202
+ ```vue
203
+ <script setup lang="ts">
204
+ import { FeedList, type FeedListItem } from '@onereach/idw-ui-components';
205
+
206
+ const items: FeedListItem[] = [
207
+ { id: '1', title: 'Hello', type: 'markdown', content: '**Hi**', shortContent: 'Preview' },
208
+ { id: '2', title: 'App', type: 'html', content: '<h1>App</h1>' },
209
+ { id: '3', title: 'Doc', type: 'file', fileUrl: 'https://example.com/a.html' },
210
+ {
211
+ id: '4',
212
+ title: 'Skill news',
213
+ type: 'skill',
214
+ content: 'Details…',
215
+ skillId: 'skill-1',
216
+ skill: { id: 'skill-1', name: 'Vacation', image: '/s.png', domain: 'HR' },
217
+ startSkillLabel: 'Open Skill',
218
+ },
219
+ {
220
+ id: '5',
221
+ title: 'Approval',
222
+ type: 'card',
223
+ source: {
224
+ templateId: 'approval',
225
+ data: { title: 'Time off', summary: 'Approve vacation.', requester: 'Ada' },
226
+ },
227
+ },
228
+ ];
229
+ </script>
230
+
231
+ <template>
232
+ <FeedList
233
+ class="h-full"
234
+ :items="items"
235
+ :loading="false"
236
+ :loading-more="false"
237
+ empty-label="No posts yet"
238
+ item-class="mx-md"
239
+ :control-labels="{ fullscreen: 'Open in fullscreen' }"
240
+ @reach-bottom="loadMore"
241
+ @fullscreen="openFullscreen"
242
+ @start-skill="openSkill"
243
+ @skill-click="openSkillOverview"
244
+ @action="onCardAction"
245
+ >
246
+ <template #header>
247
+ <!-- Optional host header -->
248
+ </template>
249
+
250
+ <template #footer="{ item }">
251
+ <!-- Host reactions / comments (shown only while expanded) -->
252
+ </template>
253
+ </FeedList>
254
+ </template>
255
+ ```
256
+
257
+ ### Props
258
+
259
+ | Prop | Type | Default | Description |
260
+ |------|------|---------|-------------|
261
+ | `items` | `FeedListItem[]` | — | Discriminated rows to render |
262
+ | `loading` | `boolean` | `false` | Replaces the list with a loader |
263
+ | `loadingMore` | `boolean` | `false` | Footer loader under existing items |
264
+ | `emptyLabel` | `string` | `No posts yet` | Shown when `items` is empty (unless `#empty`) |
265
+ | `controlLabels` | `FeedItemControlLabels` | — | Shared shell control tooltips |
266
+ | `reachBottomOffset` | `number` | `500` | Px from bottom; `reach-bottom` is edge-triggered |
267
+ | `itemClass` | `string` | — | Extra class on each `FeedItemBase` |
268
+ | `cardHostConfig` | `Partial<IdwCardHostConfig>` | — | Theme / embed size for `type: 'card'` rows |
269
+
270
+ `FeedListItem` is a discriminated union on `type`:
271
+
272
+ - `markdown` / `html` — require `content: string`
273
+ - `skill` — requires `content: string`; optional `skill` (`SkillCardData`) for the built-in card
274
+ - `file` — requires `fileUrl: string`
275
+ - `card` — requires `source` (`{ card }` or `{ templateId, data }`). Do not add `approval` / `task` as extra `type`s.
276
+ - Shell fields are picked from `FeedItemBaseProps` (`timestampDatetime`, `fullscreenControl`, `mentionControl`, `isNew`, …)
277
+ - Optional `engagement` (`FeedItemEngagement`) drives the built-in meta footer (reactions / comments / reading time) at the end of an **expanded** item
278
+
279
+ HTML/file rows get `fullscreenControl` by default and an unconstrained body max-height.
280
+ `mentionControl` defaults to `true` when omitted.
281
+
282
+ ### Slots
283
+
284
+ - `header` — above the scroll region
285
+ - `actions` / `controls` / `footer` — scoped `{ item }`, forwarded to `FeedItemBase` (`#footer` is shown only while the item body is open — use for reactions / comments)
286
+ - `empty` / `loading` / `loading-more` — replace defaults
287
+
288
+ ### Events
289
+
290
+ - `reach-bottom` — crossed into the near-end scroll zone (host loads next page)
291
+ - `fullscreen` / `start-skill` / `skill-click` / `control-click` / `expand` / `collapse` — item payloads
292
+ - `action` — `(item, event)` from a `type: 'card'` row (`verb`, `inputs`, …). Host performs the side effect.
293
+ - `update:item-expanded` — `(item, expanded)` when a row expand state changes
294
+
295
+ ## IDW Cards
296
+
297
+ Schema-driven body documents for feed items, canvas, and other hosts. This is **not** Adaptive Cards. `FeedItemBase` / `FeedList` stay host chrome (envelope). `CardRenderer` renders **body + actions** only.
298
+
299
+ The `idw.card` schema and authoring skill live in [`@onereach/idw-contracts`](../contracts). Agents that **author** card JSON (or `templateId` + data) should follow [`../contracts/skills/idw-card-authoring/SKILL.md`](../contracts/skills/idw-card-authoring/SKILL.md). Hosts that **render** cards use `CardRenderer` below. This package re-exports the schema so existing imports keep working.
300
+
301
+ Three layers:
302
+
303
+ | Layer | Role |
304
+ |---|---|
305
+ | Card schema (`idw.card` / `1.0`) | Allowed elements, actions, nesting, and URLs |
306
+ | Template | A reusable card document with `${path}` / `$when` bindings |
307
+ | Template data schema | Domain payload for that template (e.g. approval) |
308
+
309
+ The card JSON has no theme or raw colors. The host passes `hostConfig.theme` (`dark` default). Surfaces always use paired light + `dark:` token classes.
310
+
311
+ ```vue
312
+ <script setup lang="ts">
313
+ import {
314
+ CardRenderer,
315
+ cardFromMarkdown,
316
+ type IdwCardActionEvent,
317
+ } from '@onereach/idw-ui-components';
318
+
319
+ function onAction(event: IdwCardActionEvent) {
320
+ // host owns approve / reject / start-skill / …
321
+ }
322
+ </script>
323
+
324
+ <template>
325
+ <CardRenderer
326
+ :source="{
327
+ templateId: 'approval',
328
+ data: {
329
+ title: 'Time off',
330
+ summary: 'Approve vacation next Friday.',
331
+ requester: 'Ada Lovelace',
332
+ dueAt: 'Friday',
333
+ },
334
+ }"
335
+ @action="onAction"
336
+ />
337
+
338
+ <CardRenderer :source="{ card: cardFromMarkdown('**Hello**') }" />
339
+ </template>
340
+ ```
341
+
342
+ ### v1 elements
343
+
344
+ Layout / content: `Text` (Markdown), `Image`, `ImageSet`, `FactSet`, `Container`, `ColumnSet` (2–3 columns), `Table`, `Media`, `Html`, `File`, `Skill`, `ActionSet`, `Badge`, `Icon`, `Progress`.
345
+
346
+ Inputs (inspired by Adaptive Cards `Input.*`, plus IDW widgets). Every input has `name` (collected on action), plus optional `label`, `hint`, `required`, `errorMessage`, `disabled`:
347
+
348
+ | Type | Renders as | Notes |
349
+ |---|---|---|
350
+ | `Input.Text` | `OrInputV3` / `OrTextareaV3` | `multiline`, `style`: text/email/url/tel/password |
351
+ | `Input.Number` | `OrInputV3` | `min` / `max` / `step` |
352
+ | `Input.Toggle` | `OrSwitchV3` | boolean |
353
+ | `Input.Checkbox` | `OrCheckboxV3` | boolean |
354
+ | `Input.ChoiceSet` | select / radio / checkbox group | `style`: compact / expanded / filtered; `multi` |
355
+ | `Input.Date` | `OrDatePickerV3` | ISO date string |
356
+ | `Input.Time` | `OrTimePickerV3` | `HH:mm` |
357
+ | `Input.DateTime` | `OrDateTimePickerV3` | ISO datetime |
358
+ | `Input.Slider` | `OrSliderV3` | number |
359
+ | `Input.Range` | `OrRangeSliderV3` | `[from, to]` |
360
+ | `Input.Rating` | `OrRatingV3` | number |
361
+ | `Input.Location` | address (+ optional lat/lng) | `{ address, lat?, lng? }` |
362
+
363
+ Spacing: `none | xs | sm | md | lg | xl`. Text style: `caption | body | headline`. Tone: `default | emphasis | success | warning | attention`.
364
+
365
+ This is **not** Adaptive Cards JSON. We borrowed the input/container/action model (including ChoiceSet, Table, Media, ImageSet, ShowCard, ToggleVisibility) and mapped it onto or-components.
366
+
367
+ Not in v1 (AC/Copilot extras we skipped on purpose): Refresh, Authentication, Carousel, Charts, `Data.Query` remote choices, `selectAction`, `RichTextBlock` runs, and `Action.Execute`. `Input.Location` has no or-component — it is address text plus optional lat/lng, not a map picker.
368
+
369
+ ### Closed actions
370
+
371
+ `open-url`, `approve`, `reject`, `submit`, `start-skill`, `mention`, `open-conversation`, `toggle-visibility` (`targetIds`), `show-card` (`card`).
372
+
373
+ `CardRenderer` emits `action` `{ verb, title, data?, url?, skillId?, targetIds?, card?, inputs? }` and forwards `skill-click`. `approve` / `reject` / `submit` validate required inputs first and attach the current `inputs` map. The host performs the side effect.
374
+
375
+ Helpers: `cardFromMarkdown`, `cardFromHtml`, `cardFromFile`, `cardFromSkill`, `validateIdwCard`, `bindIdwCard`, `resolveCardRendererSource`.
376
+
377
+ Html/file embeds reuse `FEED_EMBED_SANDBOX` and it is not configurable from the card.