@salemcobalt/ui 0.2.0-rc.12 → 0.2.0-rc.14

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/dist/index.js CHANGED
@@ -442,7 +442,19 @@ function XIcon(props) {
442
442
 
443
443
  // src/components/Dialog/Dialog.tsx
444
444
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
445
- function Root({ dismissible = true, onOpenChange, open, defaultOpen, children }) {
445
+ var REQUESTABLE = /* @__PURE__ */ new Set([
446
+ "escape-key",
447
+ "outside-press",
448
+ "close-press"
449
+ ]);
450
+ function Root({
451
+ dismissible = true,
452
+ onOpenChange,
453
+ onRequestClose,
454
+ open,
455
+ defaultOpen,
456
+ children
457
+ }) {
446
458
  return /* @__PURE__ */ jsx6(
447
459
  BaseDialog.Root,
448
460
  {
@@ -454,6 +466,11 @@ function Root({ dismissible = true, onOpenChange, open, defaultOpen, children })
454
466
  details.cancel();
455
467
  return;
456
468
  }
469
+ if (!next && onRequestClose && REQUESTABLE.has(details.reason)) {
470
+ details.cancel();
471
+ onRequestClose(details.reason);
472
+ return;
473
+ }
457
474
  onOpenChange?.(next);
458
475
  },
459
476
  children
@@ -3133,6 +3150,332 @@ function BroomIcon({ sweeping = false, size = "lg", title, className, ...rest })
3133
3150
  );
3134
3151
  }
3135
3152
 
3153
+ // src/components/FullScreenFlow/FullScreenFlow.tsx
3154
+ import {
3155
+ Children as Children2,
3156
+ createContext as createContext2,
3157
+ useCallback as useCallback2,
3158
+ useContext as useContext2,
3159
+ useEffect as useEffect6,
3160
+ useId as useId5,
3161
+ useMemo as useMemo3,
3162
+ useRef as useRef6,
3163
+ useState as useState8
3164
+ } from "react";
3165
+ import { jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
3166
+ var FlowContext = createContext2({ announce: () => {
3167
+ } });
3168
+ var FrameContext = createContext2(void 0);
3169
+ var ENTER_IGNORES = 'textarea, button, a[href], summary, select, [contenteditable], [role="combobox"], [data-flow-keys="local"]';
3170
+ var ARROW_IGNORES = 'input, textarea, select, button, a[href], summary, [contenteditable], [role="radiogroup"], [role="slider"], [role="listbox"], [role="tablist"], [role="menu"], [role="grid"], [role="combobox"], [data-flow-keys="local"]';
3171
+ function Root7({
3172
+ open = true,
3173
+ onRequestClose,
3174
+ onNext,
3175
+ onBack,
3176
+ decoration,
3177
+ className,
3178
+ children
3179
+ }) {
3180
+ const popupRef = useRef6(null);
3181
+ const [message, setMessage] = useState8("");
3182
+ const timer = useRef6(void 0);
3183
+ const announce = useCallback2((next) => {
3184
+ setMessage("");
3185
+ clearTimeout(timer.current);
3186
+ timer.current = setTimeout(() => setMessage(next), 30);
3187
+ }, []);
3188
+ useEffect6(() => () => clearTimeout(timer.current), []);
3189
+ const context = useMemo3(() => ({ announce }), [announce]);
3190
+ const handleKeyDown = (event) => {
3191
+ if (event.defaultPrevented || event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;
3192
+ if (event.nativeEvent.isComposing) return;
3193
+ const target = event.target;
3194
+ if (!event.currentTarget.contains(target)) return;
3195
+ if (event.key === "Enter") {
3196
+ if (!onNext || target.closest(ENTER_IGNORES)) return;
3197
+ event.preventDefault();
3198
+ onNext();
3199
+ return;
3200
+ }
3201
+ if (event.key !== "ArrowRight" && event.key !== "ArrowLeft") return;
3202
+ if (target.closest(ARROW_IGNORES)) return;
3203
+ const rtl = getComputedStyle(event.currentTarget).direction === "rtl";
3204
+ const forward = event.key === "ArrowRight" !== rtl;
3205
+ const handler = forward ? onNext : onBack;
3206
+ if (!handler) return;
3207
+ event.preventDefault();
3208
+ handler();
3209
+ };
3210
+ return /* @__PURE__ */ jsx34(
3211
+ Dialog.Root,
3212
+ {
3213
+ open,
3214
+ onRequestClose: (reason) => {
3215
+ if (reason !== "outside-press") onRequestClose(reason);
3216
+ },
3217
+ children: /* @__PURE__ */ jsx34(
3218
+ Dialog.Content,
3219
+ {
3220
+ ref: popupRef,
3221
+ variant: "fullscreen",
3222
+ className: cx("sc-flow", className),
3223
+ initialFocus: () => popupRef.current?.querySelector(".sc-flow__step-title") ?? true,
3224
+ onKeyDown: handleKeyDown,
3225
+ children: /* @__PURE__ */ jsxs29(FlowContext.Provider, { value: context, children: [
3226
+ decoration ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__decoration", "aria-hidden": "true", children: decoration }) : null,
3227
+ children,
3228
+ /* @__PURE__ */ jsx34("div", { className: "sc-visually-hidden", "aria-live": "polite", "aria-atomic": "true", children: message })
3229
+ ] })
3230
+ }
3231
+ )
3232
+ }
3233
+ );
3234
+ }
3235
+ function Header2({
3236
+ title,
3237
+ logo,
3238
+ compactTitle,
3239
+ status,
3240
+ closeLabel = "Close",
3241
+ className,
3242
+ children,
3243
+ ...rest
3244
+ }) {
3245
+ return /* @__PURE__ */ jsxs29("div", { className: cx("sc-flow__header", className), ...rest, children: [
3246
+ /* @__PURE__ */ jsxs29("div", { className: "sc-flow__heading", "data-compact": compactTitle ? "" : void 0, children: [
3247
+ logo ? /* @__PURE__ */ jsx34("span", { className: "sc-flow__logo", "aria-hidden": "true", children: logo }) : null,
3248
+ /* @__PURE__ */ jsx34(Dialog.Title, { className: "sc-flow__title", children: title }),
3249
+ compactTitle ? /* @__PURE__ */ jsx34("span", { className: "sc-flow__compact-title", children: compactTitle }) : null
3250
+ ] }),
3251
+ children,
3252
+ status ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__status", children: status }) : null,
3253
+ /* @__PURE__ */ jsx34(
3254
+ Dialog.Close,
3255
+ {
3256
+ className: "sc-flow__close",
3257
+ render: /* @__PURE__ */ jsx34(IconButton, { label: closeLabel, "aria-keyshortcuts": "Escape" }),
3258
+ children: /* @__PURE__ */ jsx34(XIcon, { size: "lg" })
3259
+ }
3260
+ )
3261
+ ] });
3262
+ }
3263
+ function Progress2({
3264
+ chapters,
3265
+ step,
3266
+ label,
3267
+ listLabel = "Progress",
3268
+ className,
3269
+ ...rest
3270
+ }) {
3271
+ const starts = chapters.reduce(
3272
+ (acc, chapter, i) => [...acc, i === 0 ? 0 : acc[i - 1] + chapters[i - 1].steps],
3273
+ []
3274
+ );
3275
+ return /* @__PURE__ */ jsxs29("div", { className: cx("sc-flow__progress", className), ...rest, children: [
3276
+ label ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__progress-label", children: label }) : null,
3277
+ /* @__PURE__ */ jsx34("ol", { className: "sc-flow__segments", "aria-label": listLabel, children: chapters.map((chapter, i) => {
3278
+ const from = starts[i];
3279
+ const current = step > from && step <= from + chapter.steps;
3280
+ const done = Math.min(chapter.steps, Math.max(0, step - 1 - from)) + (current ? 0.5 : 0);
3281
+ const percent = chapter.steps > 0 ? Math.min(100, done / chapter.steps * 100) : 0;
3282
+ return /* @__PURE__ */ jsxs29(
3283
+ "li",
3284
+ {
3285
+ className: "sc-flow__segment",
3286
+ style: { flexGrow: chapter.steps },
3287
+ "aria-current": current ? "step" : void 0,
3288
+ children: [
3289
+ /* @__PURE__ */ jsx34("span", { className: "sc-flow__segment-fill", style: { inlineSize: `${percent}%` } }),
3290
+ /* @__PURE__ */ jsx34("span", { className: "sc-visually-hidden", children: chapter.label })
3291
+ ]
3292
+ },
3293
+ chapter.label
3294
+ );
3295
+ }) })
3296
+ ] });
3297
+ }
3298
+ function Body3({ className, ...rest }) {
3299
+ return /* @__PURE__ */ jsx34("div", { className: cx("sc-flow__body", className), ...rest });
3300
+ }
3301
+ function Rail({
3302
+ "aria-label": ariaLabel = "Steps",
3303
+ footer,
3304
+ className,
3305
+ children,
3306
+ ...rest
3307
+ }) {
3308
+ return /* @__PURE__ */ jsxs29("nav", { className: cx("sc-flow__rail", className), "aria-label": ariaLabel, ...rest, children: [
3309
+ children,
3310
+ footer ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__rail-note", children: footer }) : null
3311
+ ] });
3312
+ }
3313
+ function RailGroup({ label, className, children, ...rest }) {
3314
+ const id = useId5();
3315
+ return /* @__PURE__ */ jsxs29("div", { className: cx("sc-flow__rail-group", className), ...rest, children: [
3316
+ /* @__PURE__ */ jsx34("span", { className: "sc-flow__rail-label", id, children: label }),
3317
+ /* @__PURE__ */ jsx34("ol", { className: "sc-flow__rail-list", "aria-labelledby": id, children })
3318
+ ] });
3319
+ }
3320
+ function RailItem({
3321
+ current = false,
3322
+ done = false,
3323
+ doneLabel = "done",
3324
+ adornment,
3325
+ type = "button",
3326
+ className,
3327
+ children,
3328
+ ...rest
3329
+ }) {
3330
+ return /* @__PURE__ */ jsx34("li", { className: "sc-flow__rail-entry", children: /* @__PURE__ */ jsxs29(
3331
+ "button",
3332
+ {
3333
+ type,
3334
+ className: cx("sc-flow__rail-item", className),
3335
+ "aria-current": current ? "step" : void 0,
3336
+ "data-done": done || void 0,
3337
+ ...rest,
3338
+ children: [
3339
+ /* @__PURE__ */ jsx34("span", { className: "sc-flow__rail-mark", "aria-hidden": "true", children: done ? /* @__PURE__ */ jsx34(CheckIcon, { size: "sm" }) : null }),
3340
+ /* @__PURE__ */ jsxs29("span", { className: "sc-flow__rail-text", children: [
3341
+ children,
3342
+ done ? /* @__PURE__ */ jsxs29("span", { className: "sc-visually-hidden", children: [
3343
+ ", ",
3344
+ doneLabel
3345
+ ] }) : null
3346
+ ] }),
3347
+ adornment ? /* @__PURE__ */ jsx34("span", { className: "sc-flow__rail-adornment", children: adornment }) : null
3348
+ ]
3349
+ }
3350
+ ) });
3351
+ }
3352
+ function Viewport2({ direction = "forward", className, children, ...rest }) {
3353
+ const element = Children2.only(children);
3354
+ const key = String(element.key ?? "");
3355
+ const [state, setState] = useState8({
3356
+ current: { key, element, direction },
3357
+ leaving: null,
3358
+ moved: false
3359
+ });
3360
+ if (state.current.key !== key) {
3361
+ setState({
3362
+ current: { key, element, direction },
3363
+ leaving: { ...state.current, direction },
3364
+ moved: true
3365
+ });
3366
+ } else if (state.current.element !== element) {
3367
+ setState((s) => ({ ...s, current: { ...s.current, element } }));
3368
+ }
3369
+ const finishExit = useCallback2((leftKey) => {
3370
+ setState((s) => s.leaving?.key === leftKey ? { ...s, leaving: null } : s);
3371
+ }, []);
3372
+ const ref = useRef6(null);
3373
+ useEffect6(() => {
3374
+ if (state.moved && ref.current) ref.current.scrollTop = 0;
3375
+ }, [key, state.moved]);
3376
+ const frames = [];
3377
+ if (state.leaving && state.leaving.key !== key) frames.push({ frame: state.leaving, phase: "exit" });
3378
+ frames.push({
3379
+ frame: { key, element, direction: state.current.direction },
3380
+ phase: state.moved ? "enter" : void 0
3381
+ });
3382
+ return /* @__PURE__ */ jsx34("div", { ref, className: cx("sc-flow__viewport", className), ...rest, children: frames.map(({ frame, phase }) => /* @__PURE__ */ jsx34(
3383
+ FrameView,
3384
+ {
3385
+ frameKey: frame.key,
3386
+ phase,
3387
+ direction: frame.direction,
3388
+ onExited: finishExit,
3389
+ children: frame.element
3390
+ },
3391
+ frame.key
3392
+ )) });
3393
+ }
3394
+ function FrameView({
3395
+ frameKey,
3396
+ phase,
3397
+ direction,
3398
+ onExited,
3399
+ children
3400
+ }) {
3401
+ const ref = useRef6(null);
3402
+ useEffect6(() => {
3403
+ if (phase !== "exit") return;
3404
+ let cancelled = false;
3405
+ const el = ref.current;
3406
+ const animations = el && typeof el.getAnimations === "function" ? el.getAnimations() : [];
3407
+ const done = () => {
3408
+ if (!cancelled) onExited(frameKey);
3409
+ };
3410
+ Promise.all(animations.map((a) => a.finished)).then(done, done);
3411
+ return () => {
3412
+ cancelled = true;
3413
+ };
3414
+ }, [phase, frameKey, onExited]);
3415
+ return /* @__PURE__ */ jsx34(
3416
+ "div",
3417
+ {
3418
+ ref,
3419
+ className: "sc-flow__frame",
3420
+ "data-phase": phase,
3421
+ "data-direction": direction,
3422
+ inert: phase === "exit",
3423
+ children: /* @__PURE__ */ jsx34(FrameContext.Provider, { value: phase, children })
3424
+ }
3425
+ );
3426
+ }
3427
+ function Step({
3428
+ title,
3429
+ eyebrow,
3430
+ description,
3431
+ announcement,
3432
+ className,
3433
+ children,
3434
+ ...rest
3435
+ }) {
3436
+ const id = useId5();
3437
+ const titleRef = useRef6(null);
3438
+ const phase = useContext2(FrameContext);
3439
+ const { announce } = useContext2(FlowContext);
3440
+ const message = announcement ?? (typeof title === "string" ? title : void 0);
3441
+ const latest = useRef6({ message, announce });
3442
+ useEffect6(() => {
3443
+ latest.current = { message, announce };
3444
+ });
3445
+ useEffect6(() => {
3446
+ if (phase !== "enter") return;
3447
+ titleRef.current?.focus({ preventScroll: true });
3448
+ if (latest.current.message) latest.current.announce(latest.current.message);
3449
+ }, [phase]);
3450
+ return /* @__PURE__ */ jsxs29("section", { className: cx("sc-flow__step", className), "aria-labelledby": id, ...rest, children: [
3451
+ /* @__PURE__ */ jsxs29("div", { className: "sc-flow__step-head", children: [
3452
+ eyebrow ? /* @__PURE__ */ jsx34("p", { className: "sc-flow__eyebrow", children: eyebrow }) : null,
3453
+ /* @__PURE__ */ jsx34("h2", { className: "sc-flow__step-title", id, ref: titleRef, tabIndex: -1, children: title }),
3454
+ description ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__step-description", children: description }) : null
3455
+ ] }),
3456
+ children
3457
+ ] });
3458
+ }
3459
+ function Footer({ back, hint, className, children, ...rest }) {
3460
+ return /* @__PURE__ */ jsxs29("div", { className: cx("sc-flow__footer", className), ...rest, children: [
3461
+ back ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__footer-back", children: back }) : null,
3462
+ hint ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__footer-hint", children: hint }) : null,
3463
+ /* @__PURE__ */ jsx34("div", { className: "sc-flow__footer-actions", children })
3464
+ ] });
3465
+ }
3466
+ var FullScreenFlow = {
3467
+ Root: Root7,
3468
+ Header: Header2,
3469
+ Progress: Progress2,
3470
+ Body: Body3,
3471
+ Rail,
3472
+ RailGroup,
3473
+ RailItem,
3474
+ Viewport: Viewport2,
3475
+ Step,
3476
+ Footer
3477
+ };
3478
+
3136
3479
  // src/index.ts
3137
3480
  var version = "0.1.1";
3138
3481
  export {
@@ -3172,6 +3515,7 @@ export {
3172
3515
  FilePreviewDialog,
3173
3516
  FilterIcon,
3174
3517
  FlagIcon,
3518
+ FullScreenFlow,
3175
3519
  Heading,
3176
3520
  Icon,
3177
3521
  IconButton,