@wallarm-org/design-system 1.31.0 → 1.33.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 (69) hide show
  1. package/dist/components/CodeEditor/CodeEditorRoot.d.ts +1 -1
  2. package/dist/components/CodeEditor/engine/SearchPanel.js +17 -3
  3. package/dist/components/CodeEditor/engine/completion.d.ts +3 -3
  4. package/dist/components/CodeEditor/engine/completion.js +142 -2
  5. package/dist/components/CodeEditor/engine/index.js +21 -4
  6. package/dist/components/Stepper/Stepper.d.ts +22 -0
  7. package/dist/components/Stepper/Stepper.figma.d.ts +1 -0
  8. package/dist/components/Stepper/Stepper.figma.js +59 -0
  9. package/dist/components/Stepper/Stepper.js +34 -0
  10. package/dist/components/Stepper/StepperContent.d.ts +16 -0
  11. package/dist/components/Stepper/StepperContent.js +28 -0
  12. package/dist/components/Stepper/StepperContext.d.ts +58 -0
  13. package/dist/components/Stepper/StepperContext.js +37 -0
  14. package/dist/components/Stepper/StepperDescription.d.ts +8 -0
  15. package/dist/components/Stepper/StepperDescription.js +30 -0
  16. package/dist/components/Stepper/StepperIndicator.d.ts +9 -0
  17. package/dist/components/Stepper/StepperIndicator.js +34 -0
  18. package/dist/components/Stepper/StepperItem.d.ts +19 -0
  19. package/dist/components/Stepper/StepperItem.js +48 -0
  20. package/dist/components/Stepper/StepperList.d.ts +12 -0
  21. package/dist/components/Stepper/StepperList.js +28 -0
  22. package/dist/components/Stepper/StepperNextTrigger.d.ts +14 -0
  23. package/dist/components/Stepper/StepperNextTrigger.js +28 -0
  24. package/dist/components/Stepper/StepperPrevTrigger.d.ts +13 -0
  25. package/dist/components/Stepper/StepperPrevTrigger.js +31 -0
  26. package/dist/components/Stepper/StepperRootProvider.d.ts +18 -0
  27. package/dist/components/Stepper/StepperRootProvider.js +25 -0
  28. package/dist/components/Stepper/StepperSeparator.d.ts +7 -0
  29. package/dist/components/Stepper/StepperSeparator.js +28 -0
  30. package/dist/components/Stepper/StepperTitle.d.ts +8 -0
  31. package/dist/components/Stepper/StepperTitle.js +32 -0
  32. package/dist/components/Stepper/StepperTrigger.d.ts +16 -0
  33. package/dist/components/Stepper/StepperTrigger.js +32 -0
  34. package/dist/components/Stepper/classes.d.ts +14 -0
  35. package/dist/components/Stepper/classes.js +37 -0
  36. package/dist/components/Stepper/constants.d.ts +22 -0
  37. package/dist/components/Stepper/constants.js +23 -0
  38. package/dist/components/Stepper/index.d.ts +15 -0
  39. package/dist/components/Stepper/index.js +14 -0
  40. package/dist/components/Stepper/takeAsChildDisabled.d.ts +11 -0
  41. package/dist/components/Stepper/takeAsChildDisabled.js +17 -0
  42. package/dist/components/Stepper/types.d.ts +11 -0
  43. package/dist/components/Stepper/types.js +0 -0
  44. package/dist/components/Stepper/useStepper.d.ts +38 -0
  45. package/dist/components/Stepper/useStepper.js +58 -0
  46. package/dist/components/Table/TableBody/TableBodyVirtualizedCore.js +1 -1
  47. package/dist/components/Table/TableBody/TableBodyVirtualizedWindow.js +30 -8
  48. package/dist/components/Table/TableInner/TableInnerWindow.js +7 -2
  49. package/dist/components/Table/hooks/index.d.ts +1 -0
  50. package/dist/components/Table/hooks/index.js +1 -0
  51. package/dist/components/Table/hooks/infiniteScroll/useInfiniteScroll.d.ts +4 -2
  52. package/dist/components/Table/hooks/infiniteScroll/useInfiniteScroll.js +6 -2
  53. package/dist/components/Table/hooks/infiniteScroll/useInitialAnchor.d.ts +7 -1
  54. package/dist/components/Table/hooks/infiniteScroll/useInitialAnchor.js +4 -3
  55. package/dist/components/Table/hooks/infiniteScroll/usePrependScrollAnchor.d.ts +4 -1
  56. package/dist/components/Table/hooks/infiniteScroll/usePrependScrollAnchor.js +13 -11
  57. package/dist/components/Table/hooks/infiniteScroll/useScrollEdge.d.ts +4 -1
  58. package/dist/components/Table/hooks/infiniteScroll/useScrollEdge.js +7 -18
  59. package/dist/components/Table/hooks/useWindowScrollRoot.d.ts +26 -0
  60. package/dist/components/Table/hooks/useWindowScrollRoot.js +62 -0
  61. package/dist/components/Table/lib/index.d.ts +1 -0
  62. package/dist/components/Table/lib/index.js +1 -0
  63. package/dist/components/Table/lib/scrollRoot.d.ts +24 -0
  64. package/dist/components/Table/lib/scrollRoot.js +22 -0
  65. package/dist/components/Table/types.d.ts +4 -1
  66. package/dist/index.d.ts +1 -0
  67. package/dist/index.js +1 -0
  68. package/dist/metadata/components.json +4104 -433
  69. package/package.json +1 -1
@@ -23,7 +23,7 @@ export interface CodeEditorRootProps extends CodeEditorRootNativeProps, Testable
23
23
  * document would be seeded with the previous document's text.
24
24
  */
25
25
  documentId?: string;
26
- /** Focusable, selectable, searchable, copyable — but not editable by the user */
26
+ /** Non-editable and unfocusable content; text remains selectable, searchable and copyable */
27
27
  readOnly?: boolean;
28
28
  /** Offsets gutter numbers; `lines`, `folds`, `diagnostics` use absolute numbers */
29
29
  startingLineNumber?: number;
@@ -41,9 +41,20 @@ const SearchPanel = ({ view, query, matchCount, readOnly, testId })=>{
41
41
  ]
42
42
  });
43
43
  };
44
+ const blurReadOnlyContent = ()=>{
45
+ if (view.state.readOnly && view.hasFocus) view.contentDOM.blur();
46
+ };
47
+ const closeSearch = ()=>{
48
+ closeSearchPanel(view);
49
+ blurReadOnlyContent();
50
+ };
44
51
  const handleKeyDown = (event, onEnter)=>{
45
52
  if (event.nativeEvent.isComposing || 229 === event.keyCode) return;
46
- if (runScopeHandlers(view, event.nativeEvent, 'search-panel')) return void event.preventDefault();
53
+ if (runScopeHandlers(view, event.nativeEvent, 'search-panel')) {
54
+ event.preventDefault();
55
+ blurReadOnlyContent();
56
+ return;
57
+ }
47
58
  if ('Enter' === event.key) {
48
59
  event.preventDefault();
49
60
  onEnter(event.shiftKey);
@@ -53,7 +64,10 @@ const SearchPanel = ({ view, query, matchCount, readOnly, testId })=>{
53
64
  const handleReplaceKeyDown = (event)=>handleKeyDown(event, ()=>replaceNext(view));
54
65
  const handlePanelKeyDown = (event)=>{
55
66
  if (event.target instanceof HTMLInputElement) return;
56
- if (runScopeHandlers(view, event.nativeEvent, 'search-panel')) event.preventDefault();
67
+ if (runScopeHandlers(view, event.nativeEvent, 'search-panel')) {
68
+ event.preventDefault();
69
+ blurReadOnlyContent();
70
+ }
57
71
  };
58
72
  const canSearch = query.valid;
59
73
  return /*#__PURE__*/ jsxs("div", {
@@ -154,7 +168,7 @@ const SearchPanel = ({ view, query, matchCount, readOnly, testId })=>{
154
168
  className: "ml-auto",
155
169
  "aria-label": "Close search",
156
170
  "data-testid": slot('search-close'),
157
- onClick: ()=>closeSearchPanel(view),
171
+ onClick: closeSearch,
158
172
  children: /*#__PURE__*/ jsx(X, {})
159
173
  })
160
174
  ]
@@ -4,9 +4,9 @@ import type { CodeEditorCompletionContext, CodeEditorCompletionSource, CodeEdito
4
4
  /** Public, engine-free view of a CodeMirror completion request (spec §4). */
5
5
  export declare const buildCompletionContext: (ctx: CompletionContext, language: CodeEditorLanguage, startingLineNumber: number) => CodeEditorCompletionContext;
6
6
  /**
7
- * Autocomplete (spec §7.14): built-in HTTP source for `http`, the JSON Schema source when
8
- * `schema` is set, then consumer sources, all through `override` (language-data sources are
9
- * off). `completionKeymap` comes with `defaultKeymap: true` at `Prec.highest`, so Enter,
7
+ * Autocomplete: HTTP and JSON Schema sources, consumer sources, then language keywords and
8
+ * document words, all through `override` (language-data sources are off).
9
+ * `completionKeymap` comes with `defaultKeymap: true` at `Prec.highest`, so Enter,
10
10
  * arrows and Escape reach the open list before `indentWithTab` / fullscreen Escape.
11
11
  */
12
12
  export declare const completionExtension: (config: {
@@ -1,4 +1,4 @@
1
- import { autocompletion } from "@codemirror/autocomplete";
1
+ import { autocompletion, completeAnyWord, completeFromList } from "@codemirror/autocomplete";
2
2
  import { EditorView } from "@codemirror/view";
3
3
  import { cn } from "../../../utils/cn.js";
4
4
  import { dropdownMenuItemVariants } from "../../DropdownMenu/classes.js";
@@ -106,13 +106,153 @@ const adaptSource = (source, language, startingLineNumber)=>(ctx)=>{
106
106
  }
107
107
  };
108
108
  const reopensAfter = (completion)=>'string' == typeof completion.apply && completion.apply.endsWith(': ');
109
+ const LANGUAGE_KEYWORDS = {
110
+ json: [
111
+ 'true',
112
+ 'false',
113
+ 'null'
114
+ ],
115
+ yaml: [
116
+ 'true',
117
+ 'false',
118
+ 'null'
119
+ ],
120
+ bash: [
121
+ 'echo',
122
+ 'export',
123
+ 'if',
124
+ 'then',
125
+ 'else',
126
+ 'fi',
127
+ 'for',
128
+ 'in',
129
+ 'do',
130
+ 'done',
131
+ 'function'
132
+ ],
133
+ javascript: [
134
+ 'const',
135
+ 'let',
136
+ 'var',
137
+ 'function',
138
+ 'return',
139
+ 'if',
140
+ 'else',
141
+ 'for',
142
+ 'while',
143
+ 'class',
144
+ 'import',
145
+ 'export',
146
+ 'from',
147
+ 'async',
148
+ 'await',
149
+ 'true',
150
+ 'false',
151
+ 'null',
152
+ 'undefined'
153
+ ],
154
+ typescript: [
155
+ 'const',
156
+ 'let',
157
+ 'function',
158
+ 'return',
159
+ 'if',
160
+ 'else',
161
+ 'class',
162
+ 'import',
163
+ 'export',
164
+ 'from',
165
+ 'async',
166
+ 'await',
167
+ 'interface',
168
+ 'type',
169
+ 'enum',
170
+ 'extends',
171
+ 'implements',
172
+ 'public',
173
+ 'private',
174
+ 'readonly',
175
+ 'true',
176
+ 'false',
177
+ 'null',
178
+ 'undefined'
179
+ ],
180
+ python: [
181
+ 'def',
182
+ 'class',
183
+ 'return',
184
+ 'if',
185
+ 'elif',
186
+ 'else',
187
+ 'for',
188
+ 'while',
189
+ 'in',
190
+ 'import',
191
+ 'from',
192
+ 'as',
193
+ 'async',
194
+ 'await',
195
+ 'try',
196
+ 'except',
197
+ 'with',
198
+ 'True',
199
+ 'False',
200
+ 'None'
201
+ ],
202
+ lua: [
203
+ 'function',
204
+ 'local',
205
+ 'return',
206
+ 'if',
207
+ 'then',
208
+ 'elseif',
209
+ 'else',
210
+ 'end',
211
+ 'for',
212
+ 'while',
213
+ 'do',
214
+ 'repeat',
215
+ 'until',
216
+ 'true',
217
+ 'false',
218
+ 'nil'
219
+ ]
220
+ };
221
+ const isInsideQuotedString = (text)=>{
222
+ let quoted = false;
223
+ for(let i = 0; i < text.length; i++)if ('\\' === text[i]) i++;
224
+ else if ('"' === text[i]) quoted = !quoted;
225
+ return quoted;
226
+ };
227
+ const builtInSources = (language)=>{
228
+ const keywords = LANGUAGE_KEYWORDS[language];
229
+ if (!keywords) return [
230
+ completeAnyWord
231
+ ];
232
+ const completeKeywords = completeFromList(keywords.map((label)=>({
233
+ label,
234
+ type: 'keyword'
235
+ })));
236
+ if ('json' === language) return [
237
+ (ctx)=>{
238
+ const line = ctx.state.doc.lineAt(ctx.pos);
239
+ const before = line.text.slice(0, ctx.pos - line.from);
240
+ if (isInsideQuotedString(before)) return completeAnyWord(ctx);
241
+ return /(?:^|[:,\[])[\s\w]*$/.test(before) ? completeKeywords(ctx) : null;
242
+ }
243
+ ];
244
+ return [
245
+ completeKeywords,
246
+ completeAnyWord
247
+ ];
248
+ };
109
249
  const completionExtension = (config)=>{
110
250
  const { language, schema, sources, startingLineNumber } = config;
111
251
  const override = [];
112
252
  if ('http' === language) override.push(adaptSource(httpCompletions, language, startingLineNumber));
113
253
  if (void 0 !== schema && isJsonLike(language)) override.push(schemaCompletionSource(()=>schema, (state)=>jsonRegion(state, language)));
114
254
  for (const source of sources)override.push(adaptSource(source, language, startingLineNumber));
115
- if (0 === override.length) return [];
255
+ override.push(...builtInSources(language));
116
256
  return [
117
257
  autocompletion({
118
258
  override,
@@ -79,7 +79,8 @@ const SLOT_DEPS = {
79
79
  ],
80
80
  contentAttributes: [
81
81
  'contentAttributes',
82
- 'testId'
82
+ 'testId',
83
+ 'readOnly'
83
84
  ],
84
85
  cspNonce: [
85
86
  'cspNonce'
@@ -184,6 +185,7 @@ const featureExtensions = (options, callbacks)=>({
184
185
  });
185
186
  const contentAttributesFor = (options)=>{
186
187
  const attrs = sanitizeContentAttributes(options.contentAttributes);
188
+ if (options.readOnly) delete attrs.tabindex;
187
189
  if (options.testId) attrs['data-testid'] = `${options.testId}--editor`;
188
190
  return attrs;
189
191
  };
@@ -225,7 +227,10 @@ const gutterAria = [
225
227
  ];
226
228
  const slotExtensions = (options, callbacks)=>({
227
229
  language: ()=>languageExtension(options.language),
228
- readOnly: ()=>EditorState.readOnly.of(options.readOnly),
230
+ readOnly: ()=>[
231
+ EditorState.readOnly.of(options.readOnly),
232
+ EditorView.editable.of(!options.readOnly)
233
+ ],
229
234
  wrap: ()=>options.wrapLines ? EditorView.lineWrapping : [],
230
235
  maxHeight: ()=>maxHeightTheme(options.maxHeight),
231
236
  contentAttributes: ()=>EditorView.contentAttributes.of(contentAttributesFor(options)),
@@ -298,6 +303,10 @@ const createEditor = (parent, initialOptions, callbacks)=>{
298
303
  state: createState(initialOptions.value, initialOptions),
299
304
  parent
300
305
  });
306
+ const preventReadOnlyMouseFocus = (event)=>{
307
+ if (view.state.readOnly && event.target instanceof Node && view.contentDOM.contains(event.target)) event.stopPropagation();
308
+ };
309
+ view.dom.addEventListener('mousedown', preventReadOnlyMouseFocus, true);
301
310
  const ensureLazyLanguage = (lang)=>{
302
311
  if (!isLazyLanguage(lang)) return;
303
312
  loadLanguageExtension(lang).then((extension)=>{
@@ -346,13 +355,20 @@ const createEditor = (parent, initialOptions, callbacks)=>{
346
355
  const update = (next)=>{
347
356
  const prev = options;
348
357
  options = next;
349
- if (next.documentId !== prev.documentId) return void swapDocument(prev, next);
358
+ if (next.documentId !== prev.documentId) {
359
+ swapDocument(prev, next);
360
+ if (next.readOnly && view.hasFocus) view.contentDOM.blur();
361
+ return;
362
+ }
350
363
  reconfigure(prev, next);
364
+ if (next.readOnly && view.hasFocus) view.contentDOM.blur();
351
365
  if (next.language !== prev.language) ensureLazyLanguage(next.language);
352
366
  syncValue(next.value);
353
367
  };
354
368
  const api = {
355
- focus: ()=>view.focus(),
369
+ focus: ()=>{
370
+ if (!view.state.readOnly) view.focus();
371
+ },
356
372
  getValue: ()=>view.state.doc.toString(),
357
373
  insertText: (text)=>{
358
374
  if (view.state.readOnly) return;
@@ -380,6 +396,7 @@ const createEditor = (parent, initialOptions, callbacks)=>{
380
396
  destroy: ()=>{
381
397
  destroyed = true;
382
398
  cache.clear();
399
+ view.dom.removeEventListener('mousedown', preventReadOnlyMouseFocus, true);
383
400
  view.destroy();
384
401
  }
385
402
  };
@@ -0,0 +1,22 @@
1
+ import type { FC, ReactNode, Ref } from 'react';
2
+ import { Steps as ArkSteps } from '@ark-ui/react/steps';
3
+ import { type TestableProps } from '../../utils/testId';
4
+ import type { StepperStatusLabels } from './types';
5
+ import { type StepperGuardProps, type StepperOmittedArkProps } from './useStepper';
6
+ export interface StepperProps extends Omit<ArkSteps.RootProps, StepperOmittedArkProps | keyof StepperGuardProps | 'asChild'>, StepperGuardProps, TestableProps {
7
+ /** `StepperList`, then optional `StepperContent`s and `StepperPrevTrigger` / `StepperNextTrigger`. */
8
+ children: ReactNode;
9
+ /** Screen-reader-only suffixes for completed and danger steps. */
10
+ statusLabels?: StepperStatusLabels;
11
+ ref?: Ref<HTMLDivElement>;
12
+ }
13
+ /**
14
+ * A horizontal row of numbered steps for a multi-step flow, such as a create drawer. Every step is
15
+ * a button, so people can move back and forward freely; the page owns each step's status
16
+ * (completed, danger, upcoming) and the current step is always shown as active.
17
+ *
18
+ * Compound, like Ark UI Steps: `StepperList` › `StepperItem index` › `StepperTrigger` (with
19
+ * `StepperIndicator`, `StepperTitle`, `StepperDescription`) and `StepperSeparator`, then optional
20
+ * `StepperContent index`, `StepperPrevTrigger` and `StepperNextTrigger`.
21
+ */
22
+ export declare const Stepper: FC<StepperProps>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,59 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import code_connect from "@figma/code-connect";
3
+ import { Stepper } from "./Stepper.js";
4
+ import { StepperDescription } from "./StepperDescription.js";
5
+ import { StepperIndicator } from "./StepperIndicator.js";
6
+ import { StepperItem } from "./StepperItem.js";
7
+ import { StepperList } from "./StepperList.js";
8
+ import { StepperSeparator } from "./StepperSeparator.js";
9
+ import { StepperTitle } from "./StepperTitle.js";
10
+ import { StepperTrigger } from "./StepperTrigger.js";
11
+ const STEPPER_URL = 'https://www.figma.com/design/VKb5gW46uSGw0rqrhZsbXT/WADS-Components?node-id=12463-208988';
12
+ const STEPPER_ITEM_URL = 'https://www.figma.com/design/VKb5gW46uSGw0rqrhZsbXT/WADS-Components?node-id=12463-208896';
13
+ code_connect.connect(Stepper, STEPPER_URL, {
14
+ props: {
15
+ children: code_connect.children('stepper-item')
16
+ },
17
+ example: ({ children })=>/*#__PURE__*/ jsx(Stepper, {
18
+ count: 4,
19
+ step: 0,
20
+ onStepChange: ()=>void 0,
21
+ children: /*#__PURE__*/ jsx(StepperList, {
22
+ "aria-label": "Steps",
23
+ children: children
24
+ })
25
+ })
26
+ });
27
+ code_connect.connect(StepperItem, STEPPER_ITEM_URL, {
28
+ props: {
29
+ status: code_connect["enum"]('Type', {
30
+ Completed: 'completed',
31
+ Danger: 'danger',
32
+ Upcoming: 'upcoming',
33
+ Active: void 0
34
+ }),
35
+ title: code_connect.string('step'),
36
+ description: code_connect.boolean("description", {
37
+ true: code_connect.string("descriptionText"),
38
+ false: void 0
39
+ })
40
+ },
41
+ example: ({ status, title, description })=>/*#__PURE__*/ jsxs(StepperItem, {
42
+ index: 0,
43
+ status: status,
44
+ children: [
45
+ /*#__PURE__*/ jsxs(StepperTrigger, {
46
+ children: [
47
+ /*#__PURE__*/ jsx(StepperIndicator, {}),
48
+ /*#__PURE__*/ jsx(StepperTitle, {
49
+ children: title
50
+ }),
51
+ description && /*#__PURE__*/ jsx(StepperDescription, {
52
+ children: description
53
+ })
54
+ ]
55
+ }),
56
+ /*#__PURE__*/ jsx(StepperSeparator, {})
57
+ ]
58
+ })
59
+ });
@@ -0,0 +1,34 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Steps } from "@ark-ui/react/steps";
3
+ import { cn } from "../../utils/cn.js";
4
+ import { TestIdProvider } from "../../utils/testId.js";
5
+ import { stepperVariants } from "./classes.js";
6
+ import { StepperRootContext } from "./StepperContext.js";
7
+ import { useStepperGuards } from "./useStepper.js";
8
+ const Stepper = ({ children, count, step, defaultStep, onStepChange, statusLabels, className, ref, 'data-testid': testId, ...rest })=>{
9
+ const guarded = useStepperGuards({
10
+ count,
11
+ step,
12
+ defaultStep,
13
+ onStepChange
14
+ });
15
+ return /*#__PURE__*/ jsx(Steps.Root, {
16
+ ...rest,
17
+ ...guarded,
18
+ ref: ref,
19
+ "data-slot": "stepper",
20
+ "data-testid": testId,
21
+ className: cn(stepperVariants(), className),
22
+ children: /*#__PURE__*/ jsx(TestIdProvider, {
23
+ value: testId,
24
+ children: /*#__PURE__*/ jsx(StepperRootContext.Provider, {
25
+ value: {
26
+ statusLabels
27
+ },
28
+ children: children
29
+ })
30
+ })
31
+ });
32
+ };
33
+ Stepper.displayName = 'Stepper';
34
+ export { Stepper };
@@ -0,0 +1,16 @@
1
+ import type { FC, HTMLAttributes, ReactNode, Ref } from 'react';
2
+ import { type TestableProps } from '../../utils/testId';
3
+ export interface StepperContentProps extends HTMLAttributes<HTMLDivElement>, TestableProps {
4
+ /** 0-based step this body belongs to. */
5
+ index: number;
6
+ children?: ReactNode;
7
+ ref?: Ref<HTMLDivElement>;
8
+ }
9
+ /**
10
+ * The body of one step, shown only while that step is current. Every body stays mounted (hidden),
11
+ * so form state survives moving between steps. It is a `group` named by its `StepperTrigger`
12
+ * (Ark's `aria-labelledby`), so render the matching trigger in the same `Stepper`. Set trigger
13
+ * ids with the root `ids.triggerId` prop, not an `id` on `StepperTrigger`: the body only knows the
14
+ * root's ids.
15
+ */
16
+ export declare const StepperContent: FC<StepperContentProps>;
@@ -0,0 +1,28 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Steps, useStepsContext } from "@ark-ui/react/steps";
3
+ import { cn } from "../../utils/cn.js";
4
+ import { useTestId } from "../../utils/testId.js";
5
+ import { stepperContentVariants } from "./classes.js";
6
+ import { ARK_CONTENT_ARIA_RESET } from "./constants.js";
7
+ import { clampStep, useStepperRootContext } from "./StepperContext.js";
8
+ const StepperContent = ({ index, children, className, ref, 'data-testid': testIdProp, ...rest })=>{
9
+ useStepperRootContext('StepperContent');
10
+ const { value, count } = useStepsContext();
11
+ const current = index === clampStep(value, count);
12
+ const testId = useTestId(`content-${index}`, testIdProp);
13
+ return /*#__PURE__*/ jsx(Steps.Content, {
14
+ index: index,
15
+ ...ARK_CONTENT_ARIA_RESET,
16
+ role: "group",
17
+ ...rest,
18
+ ref: ref,
19
+ hidden: !current,
20
+ "data-state": current ? 'open' : 'closed',
21
+ "data-slot": "stepper-content",
22
+ "data-testid": testId,
23
+ className: cn(stepperContentVariants(), className),
24
+ children: children
25
+ });
26
+ };
27
+ StepperContent.displayName = 'StepperContent';
28
+ export { StepperContent };
@@ -0,0 +1,58 @@
1
+ import type { StepperStatusLabels, StepperVisualStatus } from './types';
2
+ interface StepperRootContextValue {
3
+ statusLabels?: StepperStatusLabels;
4
+ }
5
+ export declare const StepperRootContext: import("react").Context<StepperRootContextValue | undefined>;
6
+ /**
7
+ * Reads the enclosing `Stepper` / `StepperRootProvider`. Called first by every root-level part, so
8
+ * misuse throws a `[Stepper]` error instead of Ark's internal `useStepsContext` one.
9
+ */
10
+ export declare const useStepperRootContext: (part: string) => StepperRootContextValue;
11
+ /** `true` inside a `StepperList`, so a `StepperItem` can tell it is rendered outside one. */
12
+ export declare const StepperListContext: import("react").Context<boolean>;
13
+ export interface StepperItemContextValue {
14
+ /** 0-based position, from the item's `index` prop. */
15
+ index: number;
16
+ /** This item is the current step. */
17
+ current: boolean;
18
+ /** This item is the last step: it renders no separator. */
19
+ last: boolean;
20
+ /** Rendered state: `'active'` while current, else the item's `status`. */
21
+ status: StepperVisualStatus;
22
+ /** Screen-reader-only suffix for completed and danger steps, already resolved. */
23
+ statusLabel?: string;
24
+ }
25
+ export declare const StepperItemContext: import("react").Context<StepperItemContextValue | undefined>;
26
+ /** Reads the enclosing `StepperItem`: `{ index, current, last, status }`. */
27
+ export declare const useStepperItemContext: () => StepperItemContextValue;
28
+ /**
29
+ * The current step, clamped to `[0, count - 1]`. Zag accepts `count` as a step (its "completed"
30
+ * state, where no step is current) and checks the range only on mount, so a step can fall out of
31
+ * range; the Stepper always shows one current step.
32
+ */
33
+ export declare const clampStep: (value: number, count: number) => number;
34
+ export interface UseStepperContextReturn {
35
+ /** Current step, 0-based, always in `[0, count - 1]`. */
36
+ value: number;
37
+ /** Number of steps. */
38
+ count: number;
39
+ /** There is a later step. `false` on the last step. */
40
+ hasNextStep: boolean;
41
+ /** There is an earlier step. `false` on the first step. */
42
+ hasPrevStep: boolean;
43
+ /** Moves to the next step; does nothing on the last step. */
44
+ goToNextStep: () => void;
45
+ /** Moves to the previous step; does nothing on the first step. */
46
+ goToPrevStep: () => void;
47
+ /** Moves to the first step. */
48
+ resetStep: () => void;
49
+ /** Moves to `step`, clamped to `[0, count - 1]`. */
50
+ setStep: (step: number) => void;
51
+ }
52
+ /**
53
+ * Reads the enclosing `Stepper`. Wraps Ark's `useStepsContext`, with one difference: it never
54
+ * moves past the last step, so there is always a current step (Ark's "completed" state is not
55
+ * part of the Stepper).
56
+ */
57
+ export declare const useStepperContext: () => UseStepperContextReturn;
58
+ export {};
@@ -0,0 +1,37 @@
1
+ import { createContext, useContext } from "react";
2
+ import { useStepsContext } from "@ark-ui/react/steps";
3
+ const StepperRootContext = /*#__PURE__*/ createContext(void 0);
4
+ const useStepperRootContext = (part)=>{
5
+ const context = useContext(StepperRootContext);
6
+ if (!context) throw new Error(`[Stepper] ${part} must be used inside a Stepper or StepperRootProvider.`);
7
+ return context;
8
+ };
9
+ const StepperListContext = /*#__PURE__*/ createContext(false);
10
+ const StepperItemContext = /*#__PURE__*/ createContext(void 0);
11
+ const useStepperItemContext = ()=>{
12
+ const context = useContext(StepperItemContext);
13
+ if (!context) throw new Error('[Stepper] useStepperItemContext must be used inside a StepperItem.');
14
+ return context;
15
+ };
16
+ const clampStep = (value, count)=>Math.min(Math.max(value, 0), Math.max(count - 1, 0));
17
+ const useStepperContext = ()=>{
18
+ useStepperRootContext('useStepperContext');
19
+ const api = useStepsContext();
20
+ const value = clampStep(api.value, api.count);
21
+ const hasNextStep = value < api.count - 1;
22
+ return {
23
+ value,
24
+ count: api.count,
25
+ hasNextStep,
26
+ hasPrevStep: value > 0,
27
+ goToNextStep: ()=>{
28
+ if (hasNextStep) api.setStep(value + 1);
29
+ },
30
+ goToPrevStep: ()=>{
31
+ if (value > 0) api.setStep(value - 1);
32
+ },
33
+ resetStep: api.resetStep,
34
+ setStep: (step)=>api.setStep(clampStep(step, api.count))
35
+ };
36
+ };
37
+ export { StepperItemContext, StepperListContext, StepperRootContext, clampStep, useStepperContext, useStepperItemContext, useStepperRootContext };
@@ -0,0 +1,8 @@
1
+ import type { FC, HTMLAttributes, ReactNode, Ref } from 'react';
2
+ import { type TestableProps } from '../../utils/testId';
3
+ export interface StepperDescriptionProps extends HTMLAttributes<HTMLSpanElement>, TestableProps {
4
+ children: ReactNode;
5
+ ref?: Ref<HTMLSpanElement>;
6
+ }
7
+ /** An optional second line under the title, e.g. 'Optional' or 'Request · Lua · HMAC auth'. One line, ellipsis at 320px, with the full text in a tooltip when it overflows. */
8
+ export declare const StepperDescription: FC<StepperDescriptionProps>;
@@ -0,0 +1,30 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../../utils/cn.js";
3
+ import { useTestId } from "../../utils/testId.js";
4
+ import { OverflowTooltip, OverflowTooltipContent, OverflowTooltipTrigger } from "../OverflowTooltip/index.js";
5
+ import { stepperDescriptionVariants } from "./classes.js";
6
+ import { useStepperItemContext } from "./StepperContext.js";
7
+ const StepperDescription = ({ children, className, ref, 'data-testid': testIdProp, ...rest })=>{
8
+ const { status } = useStepperItemContext();
9
+ const testId = useTestId("description", testIdProp);
10
+ return /*#__PURE__*/ jsxs(OverflowTooltip, {
11
+ children: [
12
+ /*#__PURE__*/ jsx(OverflowTooltipTrigger, {
13
+ ref: ref,
14
+ children: /*#__PURE__*/ jsx("span", {
15
+ ...rest,
16
+ "data-slot": "stepper-description",
17
+ "data-status": status,
18
+ "data-testid": testId,
19
+ className: cn(stepperDescriptionVariants(), className),
20
+ children: children
21
+ })
22
+ }),
23
+ /*#__PURE__*/ jsx(OverflowTooltipContent, {
24
+ children: children
25
+ })
26
+ ]
27
+ });
28
+ };
29
+ StepperDescription.displayName = "StepperDescription";
30
+ export { StepperDescription };
@@ -0,0 +1,9 @@
1
+ import type { FC, HTMLAttributes, ReactNode, Ref } from 'react';
2
+ import { type TestableProps } from '../../utils/testId';
3
+ export interface StepperIndicatorProps extends HTMLAttributes<HTMLSpanElement>, TestableProps {
4
+ /** Replaces the default content: the step number, `!` for danger, a check for completed. */
5
+ children?: ReactNode;
6
+ ref?: Ref<HTMLSpanElement>;
7
+ }
8
+ /** The step badge. Decorative: Ark marks it `aria-hidden`, the title names the step. */
9
+ export declare const StepperIndicator: FC<StepperIndicatorProps>;
@@ -0,0 +1,34 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Steps } from "@ark-ui/react/steps";
3
+ import { Check } from "../../icons/index.js";
4
+ import { cn } from "../../utils/cn.js";
5
+ import { useTestId } from "../../utils/testId.js";
6
+ import { stepperIndicatorVariants } from "./classes.js";
7
+ import { useStepperItemContext } from "./StepperContext.js";
8
+ const renderDefault = (status, index)=>{
9
+ if ('completed' === status) return /*#__PURE__*/ jsx(Check, {
10
+ size: "sm"
11
+ });
12
+ if ('danger' === status) return '!';
13
+ return index + 1;
14
+ };
15
+ const StepperIndicator = ({ children, className, ref, 'data-testid': testIdProp, ...rest })=>{
16
+ const { index, status } = useStepperItemContext();
17
+ const testId = useTestId('indicator', testIdProp);
18
+ return /*#__PURE__*/ jsx(Steps.Indicator, {
19
+ asChild: true,
20
+ children: /*#__PURE__*/ jsx("span", {
21
+ ...rest,
22
+ ref: ref,
23
+ "data-slot": "stepper-indicator",
24
+ "data-status": status,
25
+ "data-testid": testId,
26
+ className: cn(stepperIndicatorVariants({
27
+ status
28
+ }), className),
29
+ children: children ?? renderDefault(status, index)
30
+ })
31
+ });
32
+ };
33
+ StepperIndicator.displayName = 'StepperIndicator';
34
+ export { StepperIndicator };