torch-glare 2.5.2 → 2.5.4

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 (51) hide show
  1. package/apps/lib/components/ActionButton.tsx +39 -6
  2. package/apps/lib/components/Badge.tsx +5 -2
  3. package/apps/lib/components/BadgeField.tsx +1 -1
  4. package/apps/lib/components/Button.tsx +4 -4
  5. package/apps/lib/components/Calendar.tsx +7 -17
  6. package/apps/lib/components/ColorPicker.tsx +1 -1
  7. package/apps/lib/components/DataViews/data-views.tsx +1 -1
  8. package/apps/lib/components/DataViews/filters/filters.tsx +1 -1
  9. package/apps/lib/components/DataViews/header.tsx +5 -2
  10. package/apps/lib/components/DataViews/panel/section.tsx +3 -1
  11. package/apps/lib/components/DataViews/views/board-view.tsx +3 -1
  12. package/apps/lib/components/DataViews/views/inbox-view.tsx +4 -1
  13. package/apps/lib/components/DataViews/views/pane-views.tsx +5 -1
  14. package/apps/lib/components/DataViews/views/table-view.tsx +67 -8
  15. package/apps/lib/components/DataViews/views/tree-view.tsx +5 -3
  16. package/apps/lib/components/Drawer.tsx +18 -1
  17. package/apps/lib/components/FormBuilder/context.ts +9 -1
  18. package/apps/lib/components/FormBuilder/submit.tsx +11 -2
  19. package/apps/lib/components/FormBuilder/types.ts +5 -1
  20. package/apps/lib/components/FormRenderer/form-renderer.tsx +15 -3
  21. package/apps/lib/components/FormRenderer/stepper.tsx +35 -14
  22. package/apps/lib/components/FormRenderer/types.ts +1 -1
  23. package/apps/lib/components/Input.tsx +19 -4
  24. package/apps/lib/components/Popover.tsx +93 -55
  25. package/apps/lib/components/SearchableSelect.tsx +12 -11
  26. package/apps/lib/components/SearchableTree.tsx +10 -11
  27. package/apps/lib/components/SearchableTreeDialog.tsx +10 -11
  28. package/apps/lib/components/SectionBlock.tsx +14 -2
  29. package/apps/lib/components/Select.tsx +35 -11
  30. package/apps/lib/components/SimpleSelect.tsx +2 -2
  31. package/apps/lib/components/SlideDatePicker.tsx +17 -4
  32. package/apps/lib/components/Stepper.tsx +329 -180
  33. package/apps/lib/components/Switch.tsx +2 -2
  34. package/apps/lib/components/Table.tsx +55 -30
  35. package/apps/lib/components/Textarea.tsx +29 -4
  36. package/apps/lib/components/TreeDropDown.tsx +18 -6
  37. package/apps/lib/components/TreeFolder/TreeFolder.tsx +61 -61
  38. package/apps/lib/registry.json +7 -16
  39. package/apps/lib/tsconfig.tsbuildinfo +1 -1
  40. package/docs/components/action-button.md +3 -1
  41. package/docs/components/data-views/index.md +7 -0
  42. package/docs/components/form-builder.md +4 -2
  43. package/docs/components/form-renderer.md +1 -1
  44. package/docs/components/stepper.md +119 -24
  45. package/docs/components/table.md +33 -0
  46. package/docs/how-to/forms-with-form-builder.md +3 -1
  47. package/docs/reference/tailwind-plugins.md +42 -0
  48. package/docs/tutorials/getting-started.md +32 -11
  49. package/package.json +1 -1
  50. package/apps/lib/components/FormStepper.tsx +0 -272
  51. package/docs/components/form-stepper.md +0 -250
@@ -1,272 +0,0 @@
1
- "use client";
2
-
3
- import React, { forwardRef, HTMLAttributes, ReactNode, createContext, useContext } from "react";
4
- import { cva } from "class-variance-authority";
5
- import { cn } from "../utils/cn";
6
- import { Themes } from "../utils/types";
7
-
8
- // ─── Types ───────────────────────────────────────────────────────────────────
9
-
10
- type FormStepperType = "default" | "success" | "negative";
11
-
12
- // ─── Context ─────────────────────────────────────────────────────────────────
13
-
14
- interface FormStepperContextValue {
15
- activeStep: number;
16
- }
17
-
18
- const FormStepperContext = createContext<FormStepperContextValue>({
19
- activeStep: 0,
20
- });
21
-
22
- const useFormStepperContext = () => useContext(FormStepperContext);
23
-
24
- // ─── FormStepper Root ────────────────────────────────────────────────────────
25
-
26
- interface FormStepperProps extends HTMLAttributes<HTMLDivElement> {
27
- theme?: Themes;
28
- activeStep?: number;
29
- }
30
-
31
- const FormStepper = forwardRef<HTMLDivElement, FormStepperProps>(
32
- ({ className, theme, activeStep = 0, ...props }, ref) => (
33
- <FormStepperContext.Provider value={{ activeStep }}>
34
- <div
35
- ref={ref}
36
- data-theme={theme}
37
- className={cn("flex items-center gap-3", className)}
38
- {...props}
39
- />
40
- </FormStepperContext.Provider>
41
- ),
42
- );
43
- FormStepper.displayName = "FormStepper";
44
-
45
- // ─── FormStep (the pill wrapper) ─────────────────────────────────────────────
46
-
47
- const formStepStyles = cva(
48
- [
49
- "group/form-step inline-flex items-center shrink-0",
50
- "h-[28px] rounded-full p-[2px]",
51
- "transition-all duration-200 ease-in-out",
52
- "cursor-pointer select-none outline-none",
53
- ],
54
- {
55
- variants: {
56
- // Selection drives the pill background. Hover drives a white bg + soft
57
- // shadow for non-selected pills, and a stronger shadow for selected pills.
58
- selected: {
59
- true: [
60
- "bg-[#000000]",
61
- "shadow-[0_0_32px_2px_rgba(0,0,0,0.05)]",
62
- "hover:shadow-[0_0_32px_2px_rgba(0,0,0,0.2)]",
63
- ],
64
- false: [
65
- "bg-transparent",
66
- "hover:bg-[#FFFFFF]",
67
- "hover:shadow-[0_0_32px_2px_rgba(0,0,0,0.05)]",
68
- ],
69
- },
70
- },
71
- defaultVariants: {
72
- selected: false,
73
- },
74
- },
75
- );
76
-
77
- interface FormStepProps extends Omit<HTMLAttributes<HTMLDivElement>, "type"> {
78
- index?: number;
79
- type?: FormStepperType;
80
- selected?: boolean;
81
- }
82
-
83
- const FormStep = forwardRef<HTMLDivElement, FormStepProps>(
84
- ({ className, index = 0, type = "default", selected, children, ...props }, ref) => {
85
- const { activeStep } = useFormStepperContext();
86
- const isSelected = selected ?? index === activeStep;
87
-
88
- return (
89
- <div
90
- ref={ref}
91
- data-selected={isSelected || undefined}
92
- data-type={type}
93
- className={cn(formStepStyles({ selected: isSelected }), className)}
94
- {...props}
95
- >
96
- {React.Children.map(children, (child) => {
97
- if (!React.isValidElement(child)) return child;
98
- return React.cloneElement(child as React.ReactElement<Record<string, unknown>>, {
99
- _selected: isSelected,
100
- _type: type,
101
- _index: index,
102
- });
103
- })}
104
- </div>
105
- );
106
- },
107
- );
108
- FormStep.displayName = "FormStep";
109
-
110
- // ─── FormStepIndicator (circle badge) ───────────────────────────────────────
111
-
112
- const formStepIndicatorStyles = cva(
113
- [
114
- "relative inline-flex items-center justify-center shrink-0",
115
- "w-[24px] h-[24px] text-[14px]",
116
- "rounded-full",
117
- "transition-colors duration-200 ease-in-out",
118
- "typography-body-medium-medium",
119
- ],
120
- {
121
- variants: {
122
- type: {
123
- default: ["border-[3px]"],
124
- success: ["bg-[#047854] text-[#FFFFFF]", "border border-transparent"],
125
- negative: ["bg-[#E30C30] text-[#FFFFFF]", "border border-transparent"],
126
- },
127
- // Only meaningful for type=default. Selected = filled blue, otherwise
128
- // ring color comes from the resting/hover compound variants below.
129
- selected: {
130
- true: "",
131
- false: "",
132
- },
133
- },
134
- defaultVariants: {
135
- type: "default",
136
- selected: false,
137
- },
138
- compoundVariants: [
139
- // Default type, not selected: gray ring + gray number at rest;
140
- // hover (driven by parent .group/form-step) flips ring blue, number black.
141
- {
142
- type: "default",
143
- selected: false,
144
- className: [
145
- "bg-transparent border-[#A0A0A0] text-[#626467]",
146
- "group-hover/form-step:border-[#004699]",
147
- "group-hover/form-step:text-[#000000]",
148
- ],
149
- },
150
- // Default type, selected: solid blue fill, white number, no ring color.
151
- {
152
- type: "default",
153
- selected: true,
154
- className: ["bg-[#005ECC] border-transparent text-[#FFFFFF]"],
155
- },
156
- ],
157
- },
158
- );
159
-
160
- const formStepIndicatorBadgeStyles = cva(
161
- [
162
- "absolute -top-[7px]",
163
- "w-[15px] h-[15px]",
164
- "rounded-full",
165
- "inline-flex items-center justify-center",
166
- "border border-[#F0F0F0]",
167
- "[&_i]:leading-none [&_i]:flex [&_i]:text-[11px]",
168
- // LTR: badge top-right; RTL: badge top-left
169
- "ltr:right-[-4px] rtl:left-[-4px]",
170
- ],
171
- {
172
- variants: {
173
- type: {
174
- success: "bg-[#047854] text-[#FFFFFF]",
175
- negative: "bg-[#E30C30] text-[#FFFFFF]",
176
- },
177
- },
178
- },
179
- );
180
-
181
- interface FormStepIndicatorProps extends HTMLAttributes<HTMLDivElement> {
182
- badgeIcon?: ReactNode;
183
- _selected?: boolean;
184
- _type?: FormStepperType;
185
- _index?: number;
186
- }
187
-
188
- const FormStepIndicator = forwardRef<HTMLDivElement, FormStepIndicatorProps>(
189
- ({ className, badgeIcon, _selected, _type = "default", _index = 0, children, ...props }, ref) => {
190
- const showBadge = _type === "success" || _type === "negative";
191
- const defaultBadgeIcon =
192
- _type === "success" ? <i className="ri-check-line" /> : <i className="ri-information-fill" />;
193
-
194
- return (
195
- <div
196
- ref={ref}
197
- className={cn(formStepIndicatorStyles({ type: _type, selected: !!_selected }), className)}
198
- {...props}
199
- >
200
- {children ?? _index + 1}
201
- {showBadge && (
202
- <span
203
- className={cn(
204
- formStepIndicatorBadgeStyles({
205
- type: _type as "success" | "negative",
206
- }),
207
- )}
208
- aria-hidden
209
- >
210
- {badgeIcon ?? defaultBadgeIcon}
211
- </span>
212
- )}
213
- </div>
214
- );
215
- },
216
- );
217
- FormStepIndicator.displayName = "FormStepIndicator";
218
-
219
- // ─── FormStepLabel ──────────────────────────────────────────────────────────
220
-
221
- const formStepLabelStyles = cva(
222
- [
223
- "typography-body-small-medium whitespace-nowrap",
224
- "transition-[padding,color] duration-200 ease-in-out",
225
- // At rest the label sits 6px from the circle. On hover (parent pill
226
- // hovered) the gap grows to 9px — matches figma onHover/onSelect-Hoverd.
227
- // The outer edge keeps a constant 12px.
228
- "ltr:pl-[6px] ltr:pr-[12px] rtl:pr-[6px] rtl:pl-[12px]",
229
- "group-hover/form-step:ltr:pl-[9px] group-hover/form-step:rtl:pr-[9px]",
230
- ],
231
- {
232
- variants: {
233
- selected: {
234
- true: "text-[#FFFFFF]",
235
- false: "text-[#000000]",
236
- },
237
- },
238
- defaultVariants: {
239
- selected: false,
240
- },
241
- },
242
- );
243
-
244
- interface FormStepLabelProps extends HTMLAttributes<HTMLDivElement> {
245
- _selected?: boolean;
246
- _type?: FormStepperType;
247
- _index?: number;
248
- }
249
-
250
- const FormStepLabel = forwardRef<HTMLDivElement, FormStepLabelProps>(
251
- // eslint-disable-next-line @typescript-eslint/no-unused-vars -- excluded from {...props} spread
252
- ({ className, _selected, _type: _t, _index: _i, ...props }, ref) => (
253
- <div
254
- ref={ref}
255
- className={cn(formStepLabelStyles({ selected: !!_selected }), className)}
256
- {...props}
257
- />
258
- ),
259
- );
260
- FormStepLabel.displayName = "FormStepLabel";
261
-
262
- // ─── Exports ─────────────────────────────────────────────────────────────────
263
-
264
- export {
265
- FormStepper,
266
- FormStep,
267
- FormStepIndicator,
268
- FormStepLabel,
269
- formStepStyles,
270
- formStepIndicatorStyles,
271
- formStepLabelStyles,
272
- };
@@ -1,250 +0,0 @@
1
- ---
2
- title: FormStepper
3
- description: Pill-shaped multi-step indicator for forms and wizards. Three semantic step types (default, success, negative) with resting, hover, selected, and selected-hover states. Full LTR and RTL support.
4
- component: true
5
- group: Forms
6
- keywords: [form-stepper, stepper, wizard, steps, pill, multi-step, form, indicator, RTL]
7
- ---
8
-
9
- # FormStepper
10
-
11
- A pill-shaped multi-step indicator for forms and wizards. Each step renders a circular indicator and a label inside a pill. Selection swaps the pill background to black with a white label; hover deepens the shadow on selected pills and grows the label gap on non-selected ones. The status badge on the indicator switches the visual to `success` (green check) or `negative` (red info).
12
-
13
- The component is composed of `FormStepper`, `FormStep`, `FormStepIndicator`, and `FormStepLabel`.
14
-
15
- ## Installation
16
-
17
- TORCH Glare is a copy-in library: the CLI copies this component's source into your project
18
- (you do **not** install it from the npm package). Run `init` once, then `add`:
19
-
20
- ```bash
21
- npx torch-glare@latest init
22
- npx torch-glare@latest add FormStepper
23
- ```
24
-
25
- `add` also copies any components, hooks, and utilities that `FormStepper` depends on.
26
-
27
- ## Imports
28
-
29
- ```typescript
30
- import {
31
- FormStepper,
32
- FormStep,
33
- FormStepIndicator,
34
- FormStepLabel,
35
- } from '@/components/FormStepper'
36
- ```
37
-
38
- ## Basic Usage
39
-
40
- ```tsx
41
- import { useState } from 'react'
42
- import {
43
- FormStepper,
44
- FormStep,
45
- FormStepIndicator,
46
- FormStepLabel,
47
- } from '@/components/FormStepper'
48
-
49
- export function BasicFormStepper() {
50
- const [activeStep, setActiveStep] = useState(0)
51
-
52
- return (
53
- <FormStepper activeStep={activeStep}>
54
- <FormStep index={0} type="success" onClick={() => setActiveStep(0)}>
55
- <FormStepIndicator />
56
- <FormStepLabel>Account</FormStepLabel>
57
- </FormStep>
58
- <FormStep index={1} type="default" onClick={() => setActiveStep(1)}>
59
- <FormStepIndicator />
60
- <FormStepLabel>Profile</FormStepLabel>
61
- </FormStep>
62
- <FormStep index={2} type="negative" onClick={() => setActiveStep(2)}>
63
- <FormStepIndicator />
64
- <FormStepLabel>Payment</FormStepLabel>
65
- </FormStep>
66
- <FormStep index={3} type="default" onClick={() => setActiveStep(3)}>
67
- <FormStepIndicator />
68
- <FormStepLabel>Confirm</FormStepLabel>
69
- </FormStep>
70
- </FormStepper>
71
- )
72
- }
73
- ```
74
-
75
- `FormStepper.activeStep` drives which pill renders selected — each `FormStep` auto-selects when its `index` matches. Pass `selected` on a step to override the match.
76
-
77
- ## Examples
78
-
79
- ### Step Types
80
-
81
- Three semantic types. `success` and `negative` add a small status badge on the indicator (check / info icon) and use filled colors when selected. `default` uses a gray ring at rest, blue ring on hover, and a solid blue fill when selected.
82
-
83
- ```tsx
84
- export function StepTypes() {
85
- return (
86
- <FormStepper>
87
- <FormStep index={0} type="default" selected={false}>
88
- <FormStepIndicator />
89
- <FormStepLabel>Default</FormStepLabel>
90
- </FormStep>
91
- <FormStep index={1} type="success" selected={false}>
92
- <FormStepIndicator />
93
- <FormStepLabel>Success</FormStepLabel>
94
- </FormStep>
95
- <FormStep index={2} type="negative" selected={false}>
96
- <FormStepIndicator />
97
- <FormStepLabel>Negative</FormStepLabel>
98
- </FormStep>
99
- </FormStepper>
100
- )
101
- }
102
- ```
103
-
104
- ### Selected state
105
-
106
- ```tsx
107
- export function SelectedSteps() {
108
- return (
109
- <FormStepper>
110
- <FormStep index={0} type="default" selected>
111
- <FormStepIndicator />
112
- <FormStepLabel>Default</FormStepLabel>
113
- </FormStep>
114
- <FormStep index={1} type="success" selected>
115
- <FormStepIndicator />
116
- <FormStepLabel>Success</FormStepLabel>
117
- </FormStep>
118
- <FormStep index={2} type="negative" selected>
119
- <FormStepIndicator />
120
- <FormStepLabel>Negative</FormStepLabel>
121
- </FormStep>
122
- </FormStepper>
123
- )
124
- }
125
- ```
126
-
127
- ### RTL direction
128
-
129
- The pill, label spacing, and indicator badge all flip under `dir="rtl"`.
130
-
131
- ```tsx
132
- export function RTLFormStepper() {
133
- return (
134
- <div dir="rtl">
135
- <FormStepper>
136
- <FormStep index={0} type="default" selected>
137
- <FormStepIndicator />
138
- <FormStepLabel>افتراضي</FormStepLabel>
139
- </FormStep>
140
- <FormStep index={1} type="success">
141
- <FormStepIndicator />
142
- <FormStepLabel>نجاح</FormStepLabel>
143
- </FormStep>
144
- <FormStep index={2} type="negative">
145
- <FormStepIndicator />
146
- <FormStepLabel>خطأ</FormStepLabel>
147
- </FormStep>
148
- </FormStepper>
149
- </div>
150
- )
151
- }
152
- ```
153
-
154
- ### Custom badge icon
155
-
156
- `FormStepIndicator.badgeIcon` overrides the default check / info icon for `success` / `negative` types.
157
-
158
- ```tsx
159
- <FormStep index={0} type="success" selected>
160
- <FormStepIndicator badgeIcon={<i className="ri-shield-check-line" />} />
161
- <FormStepLabel>Verified</FormStepLabel>
162
- </FormStep>
163
- ```
164
-
165
- ### Custom indicator content
166
-
167
- Children of `FormStepIndicator` replace the auto-rendered step number.
168
-
169
- ```tsx
170
- <FormStep index={0} type="default" selected>
171
- <FormStepIndicator>
172
- <i className="ri-user-line" />
173
- </FormStepIndicator>
174
- <FormStepLabel>Account</FormStepLabel>
175
- </FormStep>
176
- ```
177
-
178
- ## API Reference
179
-
180
- ### FormStepper
181
-
182
- | Prop | Type | Default | Description |
183
- | ------------ | ------------------------------- | ------- | ----------------------------------------------------------------- |
184
- | `activeStep` | `number` | `0` | Zero-based index of the currently selected step. |
185
- | `theme` | `'dark' \| 'light' \| 'default'` | — | Theme override applied via `data-theme`. |
186
- | `className` | `string` | — | Extra classes merged onto the root `<div>`. |
187
-
188
- Standard `HTMLAttributes<HTMLDivElement>` are forwarded.
189
-
190
- ### FormStep
191
-
192
- | Prop | Type | Default | Description |
193
- | ----------- | --------------------------------------- | ----------- | -------------------------------------------------------------------------- |
194
- | `index` | `number` | `0` | Zero-based step index. Matched against `FormStepper.activeStep`. |
195
- | `type` | `'default' \| 'success' \| 'negative'` | `'default'` | Visual type. `success` and `negative` add a status badge on the indicator. |
196
- | `selected` | `boolean` | — | Force the selected state, overriding the index/`activeStep` match. |
197
- | `className` | `string` | — | Extra classes merged onto the pill root. |
198
-
199
- Standard `HTMLAttributes<HTMLDivElement>` (minus `type`) are forwarded — typical use is `onClick` for navigation.
200
-
201
- ### FormStepIndicator
202
-
203
- | Prop | Type | Default | Description |
204
- | ----------- | ----------- | ------- | ----------------------------------------------------------------------------- |
205
- | `badgeIcon` | `ReactNode` | — | Override the default badge icon (check for `success`, info for `negative`). |
206
- | `children` | `ReactNode` | — | Replaces the auto-rendered step number. |
207
- | `className` | `string` | — | Extra classes merged onto the indicator `<div>`. |
208
-
209
- ### FormStepLabel
210
-
211
- Forwards `HTMLAttributes<HTMLDivElement>`. Color and label spacing follow the parent `FormStep` selection state.
212
-
213
- ## Styling
214
-
215
- - Pill height: `28px`, fully rounded, `2px` inner padding.
216
- - Indicator: `24×24px` circle, `border-[3px]` for `default`, solid fill for `success`/`negative`.
217
- - Status badge: `15×15px` circle pinned to the top-right of the indicator (top-left under RTL), with `border` matching the page background.
218
- - Selection: `bg-[#000000]` pill with `text-[#FFFFFF]` label and a `0 0 32px 2px rgba(0,0,0,0.05)` shadow that deepens on hover.
219
- - Non-selected hover: `bg-[#FFFFFF]` pill, label gap grows from `6px` to `9px`, ring color flips to `#004699`.
220
-
221
- ## TypeScript Types
222
-
223
- ```typescript
224
- type FormStepperType = 'default' | 'success' | 'negative'
225
-
226
- interface FormStepperProps extends React.HTMLAttributes<HTMLDivElement> {
227
- activeStep?: number
228
- theme?: 'dark' | 'light' | 'default'
229
- }
230
-
231
- interface FormStepProps
232
- extends Omit<React.HTMLAttributes<HTMLDivElement>, 'type'> {
233
- index?: number
234
- type?: FormStepperType
235
- selected?: boolean
236
- }
237
- ```
238
-
239
- ## Accessibility
240
-
241
- - Each `FormStep` is a focusable interactive surface — attach `onClick` and (if needed) `role="button"` plus `tabIndex={0}` for keyboard navigation.
242
- - The status badge is `aria-hidden`; the meaning should be carried by the label text (e.g. `"Payment — error"`).
243
- - Color is never the sole signal for `success`/`negative` — pair with text or an off-screen description.
244
-
245
- ## Best Practices
246
-
247
- 1. Drive selection with `activeStep` from the parent form state — avoid setting `selected` per step manually.
248
- 2. Use `success` only for *completed and validated* steps, `negative` only for *failed* steps. Default = pending or current.
249
- 3. Keep labels short — the pill grows by `~3px` on hover, and long labels make that animation jittery.
250
- 4. Wire `onClick` for non-linear navigation (jump-to-step). For strict wizards, omit `onClick` on future steps.