@wistia/ui 0.14.20 → 0.14.21

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.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  /*
3
- * @license @wistia/ui v0.14.20
3
+ * @license @wistia/ui v0.14.21
4
4
  *
5
5
  * Copyright (c) 2024-2025, Wistia, Inc. and its affiliates.
6
6
  *
@@ -82,6 +82,15 @@ __export(index_exports, {
82
82
  DataListItemValue: () => DataListItemValue,
83
83
  Divider: () => Divider,
84
84
  EditableHeading: () => EditableHeading,
85
+ EditableText: () => EditableText,
86
+ EditableTextCancelButton: () => EditableTextCancelButton,
87
+ EditableTextContext: () => EditableTextContext,
88
+ EditableTextDisplay: () => EditableTextDisplay,
89
+ EditableTextInput: () => EditableTextInput,
90
+ EditableTextLabel: () => EditableTextLabel,
91
+ EditableTextRoot: () => EditableTextRoot,
92
+ EditableTextSubmitButton: () => EditableTextSubmitButton,
93
+ EditableTextTrigger: () => EditableTextTrigger,
85
94
  Ellipsis: () => Ellipsis,
86
95
  FileAmountLimitValidator: () => import_validators.FileAmountLimitValidator,
87
96
  FileSizeValidator: () => import_validators.FileSizeValidator,
@@ -11334,6 +11343,7 @@ var Input = (0, import_react47.forwardRef)(
11334
11343
  {
11335
11344
  $fullWidth: fullWidth,
11336
11345
  $monospace: monospace,
11346
+ "data-wui-input-container": true,
11337
11347
  children: [
11338
11348
  leftIconToDisplay ?? null,
11339
11349
  type === "multiline" ? /* @__PURE__ */ (0, import_jsx_runtime247.jsx)(
@@ -17006,10 +17016,474 @@ var ContextMenu = ({
17006
17016
  ) : null;
17007
17017
  };
17008
17018
 
17009
- // src/components/DataList/DataList.tsx
17019
+ // src/components/EditableText/EditableTextDisplay.tsx
17020
+ var import_react92 = require("react");
17021
+ var import_styled_components123 = __toESM(require("styled-components"));
17022
+ var import_type_guards73 = require("@wistia/type-guards");
17023
+
17024
+ // src/components/EditableText/EditableTextRoot.tsx
17025
+ var import_react91 = require("react");
17026
+ var import_type_guards72 = require("@wistia/type-guards");
17010
17027
  var import_styled_components121 = __toESM(require("styled-components"));
17011
17028
  var import_jsx_runtime317 = require("react/jsx-runtime");
17012
- var StyledDataList = import_styled_components121.default.dl`
17029
+ var StyledEditableTextRoot = import_styled_components121.default.div`
17030
+ display: contents;
17031
+
17032
+ --wui-editable-text-padding: var(--wui-space-01);
17033
+ --wui-editable-text-border-radius: var(--wui-border-radius-01);
17034
+ `;
17035
+ var EditableTextContext = (0, import_react91.createContext)(null);
17036
+ var EditableTextRoot = ({
17037
+ children,
17038
+ defaultValue = "",
17039
+ value: controlledValue,
17040
+ onValueChange,
17041
+ onValueCommit,
17042
+ onValueRevert,
17043
+ onEditingChange,
17044
+ typographicVariant = "body2",
17045
+ submitMode = "both",
17046
+ readOnly = false,
17047
+ id,
17048
+ label,
17049
+ placeholder = "Click to edit this text",
17050
+ minLines = 1,
17051
+ maxLines,
17052
+ finalFocusEl,
17053
+ ...props
17054
+ }) => {
17055
+ const isControlled = controlledValue !== void 0;
17056
+ const [internalValue, setInternalValue] = (0, import_react91.useState)(defaultValue);
17057
+ const [originalValue, setOriginalValue] = (0, import_react91.useState)(defaultValue);
17058
+ const [isEditing, setIsEditing] = (0, import_react91.useState)(false);
17059
+ const value = isControlled ? controlledValue : internalValue;
17060
+ const generatedId = (0, import_react91.useId)();
17061
+ const computedId = (0, import_type_guards72.isNonEmptyString)(id) ? id : `wistia-ui-editable-text-${generatedId}`;
17062
+ const handleSetIsEditing = (0, import_react91.useCallback)(
17063
+ (editing) => {
17064
+ if (editing && !isEditing) {
17065
+ setOriginalValue(value);
17066
+ }
17067
+ setIsEditing(editing);
17068
+ onEditingChange?.(editing);
17069
+ },
17070
+ [isEditing, value, onEditingChange]
17071
+ );
17072
+ const setValue = (0, import_react91.useCallback)(
17073
+ (newValue) => {
17074
+ if (!isControlled) {
17075
+ setInternalValue(newValue);
17076
+ }
17077
+ onValueChange?.(newValue);
17078
+ },
17079
+ [isControlled, onValueChange]
17080
+ );
17081
+ const context = (0, import_react91.useMemo)(() => {
17082
+ return {
17083
+ isEditing,
17084
+ setIsEditing: handleSetIsEditing,
17085
+ value,
17086
+ setValue,
17087
+ originalValue,
17088
+ onValueCommit,
17089
+ onValueRevert,
17090
+ typographicVariant,
17091
+ submitMode,
17092
+ readOnly,
17093
+ id: computedId,
17094
+ label,
17095
+ placeholder,
17096
+ minLines,
17097
+ maxLines,
17098
+ finalFocusEl
17099
+ };
17100
+ }, [
17101
+ isEditing,
17102
+ handleSetIsEditing,
17103
+ value,
17104
+ setValue,
17105
+ originalValue,
17106
+ onValueCommit,
17107
+ onValueRevert,
17108
+ typographicVariant,
17109
+ submitMode,
17110
+ readOnly,
17111
+ computedId,
17112
+ label,
17113
+ placeholder,
17114
+ minLines,
17115
+ maxLines,
17116
+ finalFocusEl
17117
+ ]);
17118
+ const getState = () => {
17119
+ if (readOnly) {
17120
+ return "read-only";
17121
+ }
17122
+ if (isEditing) {
17123
+ return "editing";
17124
+ }
17125
+ return "idle";
17126
+ };
17127
+ return /* @__PURE__ */ (0, import_jsx_runtime317.jsx)(
17128
+ StyledEditableTextRoot,
17129
+ {
17130
+ "data-testid": "editable-text-root",
17131
+ "data-wui-editable-text-root": true,
17132
+ "data-wui-editable-text-state": getState(),
17133
+ ...props,
17134
+ children: /* @__PURE__ */ (0, import_jsx_runtime317.jsx)(EditableTextContext.Provider, { value: context, children })
17135
+ }
17136
+ );
17137
+ };
17138
+
17139
+ // src/private/helpers/getTypographicStyles/getTypographicStyles.ts
17140
+ var import_styled_components122 = require("styled-components");
17141
+ var typographicVariantStyleMap = { ...variantStyleMap2, ...variantStyleMap };
17142
+ var getTypographicStyles = (variant) => {
17143
+ return import_styled_components122.css`
17144
+ ${typographicVariantStyleMap[variant]}
17145
+ font-family: var(--font-family);
17146
+ font-size: var(--font-size);
17147
+ font-weight: var(--font-weight);
17148
+ line-height: var(--line-height);
17149
+ `;
17150
+ };
17151
+ var typographicVariantElementMap = { ...variantElementMap2, ...variantElementMap };
17152
+ var getDefaultTypographicElement = (variant) => {
17153
+ return typographicVariantElementMap[variant] ?? "span";
17154
+ };
17155
+
17156
+ // src/components/EditableText/EditableTextDisplay.tsx
17157
+ var import_jsx_runtime318 = require("react/jsx-runtime");
17158
+ var StyledEditableTextDisplay = import_styled_components123.default.div`
17159
+ ${({ $typographicVariant }) => getTypographicStyles($typographicVariant)}
17160
+ padding: var(--wui-editable-text-padding);
17161
+ border-radius: var(--wui-editable-text-border-radius);
17162
+ margin: 0;
17163
+ transition: all var(--wui-motion-duration-02) var(--wui-motion-ease);
17164
+ ${({ $maxLines }) => {
17165
+ if ((0, import_type_guards73.isNotNil)($maxLines)) {
17166
+ return import_styled_components123.css`
17167
+ ${ellipsisStyle};
17168
+ ${lineClampCss($maxLines)};
17169
+ `;
17170
+ }
17171
+ return void 0;
17172
+ }}
17173
+ ${({ $minLines }) => (0, import_type_guards73.isNotNil)($minLines) && import_styled_components123.css`
17174
+ min-height: calc(${$minLines}lh + calc(var(--wui-editable-text-padding) * 2));
17175
+ `}
17176
+ word-break: break-word;
17177
+
17178
+ &[data-wui-editable-text-display='placeholder'] {
17179
+ color: var(--wui-color-text-secondary);
17180
+ }
17181
+
17182
+ &:has(button) {
17183
+ user-select: none;
17184
+ cursor: pointer;
17185
+
17186
+ &:hover,
17187
+ &:focus-within {
17188
+ background-color: var(--wui-color-bg-surface-hover);
17189
+ }
17190
+ }
17191
+ `;
17192
+ var EditableTextDisplayComponent = (0, import_react92.forwardRef)(
17193
+ ({ asTrigger, renderAs, ...props }, ref) => {
17194
+ const context = (0, import_react92.useContext)(EditableTextContext);
17195
+ if (!context) {
17196
+ throw new Error("EditableTextDisplay must be used within an EditableTextRoot context");
17197
+ }
17198
+ const { value, typographicVariant, setIsEditing, placeholder, maxLines, isEditing, minLines } = context;
17199
+ const triggerButtonRef = (0, import_react92.useRef)(null);
17200
+ const handleTriggerClick = () => {
17201
+ setIsEditing(true);
17202
+ };
17203
+ const elementType = renderAs ?? getDefaultTypographicElement(typographicVariant);
17204
+ const displayText = value.length > 0 ? value : placeholder;
17205
+ const isPlaceholderVisible = value.length === 0 && !!placeholder;
17206
+ if (isEditing) {
17207
+ return null;
17208
+ }
17209
+ if (asTrigger && !context.readOnly) {
17210
+ return /* @__PURE__ */ (0, import_jsx_runtime318.jsx)(ClickRegion, { targetRef: triggerButtonRef, children: /* @__PURE__ */ (0, import_jsx_runtime318.jsxs)(
17211
+ StyledEditableTextDisplay,
17212
+ {
17213
+ ref,
17214
+ $maxLines: maxLines,
17215
+ $minLines: minLines,
17216
+ $typographicVariant: typographicVariant,
17217
+ as: elementType,
17218
+ "data-wui-editable-text-display": isPlaceholderVisible ? "placeholder" : "value",
17219
+ ...props,
17220
+ children: [
17221
+ displayText,
17222
+ /* @__PURE__ */ (0, import_jsx_runtime318.jsx)(
17223
+ "button",
17224
+ {
17225
+ ref: triggerButtonRef,
17226
+ onClick: handleTriggerClick,
17227
+ style: { ...visuallyHiddenStyle },
17228
+ type: "button",
17229
+ children: "Edit text"
17230
+ }
17231
+ )
17232
+ ]
17233
+ }
17234
+ ) });
17235
+ }
17236
+ return /* @__PURE__ */ (0, import_jsx_runtime318.jsx)(
17237
+ StyledEditableTextDisplay,
17238
+ {
17239
+ ref,
17240
+ $maxLines: maxLines,
17241
+ $minLines: minLines,
17242
+ $typographicVariant: typographicVariant,
17243
+ as: elementType,
17244
+ "data-placeholder-visible": isPlaceholderVisible || void 0,
17245
+ "data-wui-editable-text-display": true,
17246
+ ...props,
17247
+ children: displayText
17248
+ }
17249
+ );
17250
+ }
17251
+ );
17252
+ EditableTextDisplayComponent.displayName = "EditableTextDisplay_UI";
17253
+ var EditableTextDisplay = makePolymorphic(
17254
+ EditableTextDisplayComponent
17255
+ );
17256
+
17257
+ // src/components/EditableText/EditableTextInput.tsx
17258
+ var import_react93 = require("react");
17259
+ var import_styled_components124 = __toESM(require("styled-components"));
17260
+ var import_type_guards74 = require("@wistia/type-guards");
17261
+ var import_jsx_runtime319 = require("react/jsx-runtime");
17262
+ var StyledInput2 = (0, import_styled_components124.default)(Input)`
17263
+ && {
17264
+ ${({ $minLines }) => (0, import_type_guards74.isNotNil)($minLines) && `min-height: calc(${$minLines}lh + calc(var(--wui-editable-text-padding) * 2));`}
17265
+ ${({ $maxLines }) => (0, import_type_guards74.isNotNil)($maxLines) && `max-height: calc(${$maxLines}lh + calc(var(--wui-editable-text-padding) * 2));`}
17266
+ ${({ $typographicVariant }) => getTypographicStyles($typographicVariant)}
17267
+ padding: var(--wui-editable-text-padding);
17268
+ border-radius: var(--wui-editable-text-border-radius);
17269
+ background-color: var(--wui-color-bg-surface);
17270
+ }
17271
+ `;
17272
+ var EditableTextInput = (props) => {
17273
+ const context = (0, import_react93.useContext)(EditableTextContext);
17274
+ if (!context) {
17275
+ throw new Error("EditableTextInput must be used within an EditableTextRoot context");
17276
+ }
17277
+ const {
17278
+ isEditing,
17279
+ value,
17280
+ setValue,
17281
+ onValueCommit,
17282
+ setIsEditing,
17283
+ typographicVariant,
17284
+ submitMode,
17285
+ originalValue,
17286
+ onValueRevert,
17287
+ id,
17288
+ placeholder,
17289
+ minLines,
17290
+ maxLines,
17291
+ finalFocusEl
17292
+ } = context;
17293
+ const inputRef = (0, import_react93.useRef)(null);
17294
+ (0, import_react93.useEffect)(() => {
17295
+ if (inputRef.current) {
17296
+ if (isEditing) {
17297
+ const element = inputRef.current;
17298
+ const { style } = element;
17299
+ style.height = "0px";
17300
+ const { scrollHeight } = element;
17301
+ style.height = `${scrollHeight}px`;
17302
+ }
17303
+ if (isEditing) {
17304
+ inputRef.current.focus();
17305
+ }
17306
+ }
17307
+ }, [value, isEditing]);
17308
+ const handleChange = (event) => {
17309
+ setValue(event.target.value);
17310
+ };
17311
+ const handleKeyDown = (event) => {
17312
+ if ((submitMode === "enter" || submitMode === "both") && event.key === "Enter" && !event.shiftKey) {
17313
+ event.preventDefault();
17314
+ onValueCommit?.(value);
17315
+ setIsEditing(false);
17316
+ setTimeout(() => {
17317
+ const element = finalFocusEl?.();
17318
+ if (element) {
17319
+ element.focus();
17320
+ }
17321
+ }, 0);
17322
+ }
17323
+ if (event.key === "Escape") {
17324
+ event.preventDefault();
17325
+ setValue(originalValue);
17326
+ onValueRevert?.(originalValue);
17327
+ setIsEditing(false);
17328
+ setTimeout(() => {
17329
+ const element = finalFocusEl?.();
17330
+ if (element) {
17331
+ element.focus();
17332
+ }
17333
+ }, 0);
17334
+ }
17335
+ };
17336
+ const handleBlur2 = () => {
17337
+ if (submitMode === "blur" || submitMode === "both") {
17338
+ onValueCommit?.(value);
17339
+ setIsEditing(false);
17340
+ setTimeout(() => {
17341
+ const element = finalFocusEl?.();
17342
+ if (element) {
17343
+ element.focus();
17344
+ }
17345
+ }, 0);
17346
+ }
17347
+ };
17348
+ if (!isEditing) return null;
17349
+ return /* @__PURE__ */ (0, import_jsx_runtime319.jsx)(
17350
+ StyledInput2,
17351
+ {
17352
+ ref: inputRef,
17353
+ $maxLines: maxLines ?? "infinity",
17354
+ $minLines: minLines,
17355
+ $typographicVariant: typographicVariant,
17356
+ "data-wui-editable-text-input": true,
17357
+ id,
17358
+ onBlur: handleBlur2,
17359
+ onChange: handleChange,
17360
+ onKeyDown: handleKeyDown,
17361
+ placeholder,
17362
+ type: "multiline",
17363
+ value,
17364
+ ...props
17365
+ }
17366
+ );
17367
+ };
17368
+
17369
+ // src/components/EditableText/EditableTextLabel.tsx
17370
+ var import_react94 = require("react");
17371
+ var import_jsx_runtime320 = require("react/jsx-runtime");
17372
+ var EditableTextLabel = ({ ...props }) => {
17373
+ const context = (0, import_react94.useContext)(EditableTextContext);
17374
+ if (!context) {
17375
+ throw new Error("EditableTextLabel must be used within an EditableTextRoot context");
17376
+ }
17377
+ const { id, label } = context;
17378
+ return /* @__PURE__ */ (0, import_jsx_runtime320.jsx)(
17379
+ Label,
17380
+ {
17381
+ htmlFor: id,
17382
+ ...props,
17383
+ children: label
17384
+ }
17385
+ );
17386
+ };
17387
+
17388
+ // src/components/EditableText/EditableText.tsx
17389
+ var import_jsx_runtime321 = require("react/jsx-runtime");
17390
+ var EditableText = ({ hideLabel = true, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime321.jsxs)(EditableTextRoot, { ...props, children: [
17391
+ /* @__PURE__ */ (0, import_jsx_runtime321.jsx)(EditableTextLabel, { screenReaderOnly: hideLabel }),
17392
+ /* @__PURE__ */ (0, import_jsx_runtime321.jsx)(EditableTextInput, {}),
17393
+ /* @__PURE__ */ (0, import_jsx_runtime321.jsx)(EditableTextDisplay, { asTrigger: true })
17394
+ ] });
17395
+ EditableText.displayName = "EditableText_UI";
17396
+
17397
+ // src/components/EditableText/EditableTextSubmitButton.tsx
17398
+ var import_react95 = require("react");
17399
+ var EditableTextSubmitButton = ({
17400
+ /**
17401
+ * A submit button, typically a [Button]() that will commit the value when clicked.
17402
+ */
17403
+ children
17404
+ }) => {
17405
+ const context = (0, import_react95.useContext)(EditableTextContext);
17406
+ if (!context) {
17407
+ throw new Error("EditableTextSubmitButton must be used within an EditableTextRoot context");
17408
+ }
17409
+ const { setIsEditing, value, onValueCommit, finalFocusEl, isEditing } = context;
17410
+ const handleClick = () => {
17411
+ onValueCommit?.(value);
17412
+ setIsEditing(false);
17413
+ setTimeout(() => {
17414
+ const element = finalFocusEl?.();
17415
+ if (element) {
17416
+ element.focus();
17417
+ }
17418
+ }, 0);
17419
+ };
17420
+ const onlyChild = import_react95.Children.only(children);
17421
+ const triggerProps = {
17422
+ onClick: handleClick,
17423
+ "data-wui-editable-text-submit": true
17424
+ };
17425
+ if (!isEditing) return null;
17426
+ return (0, import_react95.cloneElement)(onlyChild, triggerProps);
17427
+ };
17428
+
17429
+ // src/components/EditableText/EditableTextCancelButton.tsx
17430
+ var import_react96 = require("react");
17431
+ var EditableTextCancelButton = ({
17432
+ children
17433
+ }) => {
17434
+ const context = (0, import_react96.useContext)(EditableTextContext);
17435
+ if (!context) {
17436
+ throw new Error("EditableTextCancelButton must be used within an EditableTextRoot context");
17437
+ }
17438
+ const { setIsEditing, originalValue, setValue, onValueRevert, finalFocusEl, isEditing } = context;
17439
+ const handleClick = () => {
17440
+ setValue(originalValue);
17441
+ onValueRevert?.(originalValue);
17442
+ setIsEditing(false);
17443
+ setTimeout(() => {
17444
+ const element = finalFocusEl?.();
17445
+ if (element) {
17446
+ element.focus();
17447
+ }
17448
+ }, 0);
17449
+ };
17450
+ const onlyChild = import_react96.Children.only(children);
17451
+ const triggerProps = {
17452
+ onClick: handleClick,
17453
+ "data-wui-editable-text-cancel": true
17454
+ };
17455
+ if (!isEditing) return null;
17456
+ return (0, import_react96.cloneElement)(onlyChild, triggerProps);
17457
+ };
17458
+
17459
+ // src/components/EditableText/EditableTextTrigger.tsx
17460
+ var import_react97 = require("react");
17461
+ var EditableTextTrigger = ({
17462
+ children,
17463
+ ...props
17464
+ }) => {
17465
+ const context = (0, import_react97.useContext)(EditableTextContext);
17466
+ if (!context) {
17467
+ throw new Error("EditableTextTrigger must be used within an EditableTextRoot context");
17468
+ }
17469
+ const { setIsEditing, isEditing } = context;
17470
+ const handleClick = () => {
17471
+ setIsEditing(true);
17472
+ };
17473
+ const onlyChild = import_react97.Children.only(children);
17474
+ const triggerProps = {
17475
+ onClick: handleClick,
17476
+ "data-wui-editable-text-trigger": true,
17477
+ ...props
17478
+ };
17479
+ if (isEditing) return null;
17480
+ return (0, import_react97.cloneElement)(onlyChild, triggerProps);
17481
+ };
17482
+
17483
+ // src/components/DataList/DataList.tsx
17484
+ var import_styled_components125 = __toESM(require("styled-components"));
17485
+ var import_jsx_runtime322 = require("react/jsx-runtime");
17486
+ var StyledDataList = import_styled_components125.default.dl`
17013
17487
  display: grid;
17014
17488
  grid-template-columns: auto 1fr;
17015
17489
  column-gap: var(--wui-space-02);
@@ -17037,7 +17511,7 @@ var DataList = ({
17037
17511
  labelProminence = "primary",
17038
17512
  ...props
17039
17513
  }) => {
17040
- return /* @__PURE__ */ (0, import_jsx_runtime317.jsx)(
17514
+ return /* @__PURE__ */ (0, import_jsx_runtime322.jsx)(
17041
17515
  StyledDataList,
17042
17516
  {
17043
17517
  role: "list",
@@ -17060,9 +17534,9 @@ var DataListItem = ({ children }) => {
17060
17534
  DataListItem.displayName = "DataListItem_UI";
17061
17535
 
17062
17536
  // src/components/DataList/DataListItemLabel.tsx
17063
- var import_jsx_runtime318 = require("react/jsx-runtime");
17537
+ var import_jsx_runtime323 = require("react/jsx-runtime");
17064
17538
  var DataListItemLabel = (props) => {
17065
- return /* @__PURE__ */ (0, import_jsx_runtime318.jsx)(
17539
+ return /* @__PURE__ */ (0, import_jsx_runtime323.jsx)(
17066
17540
  Text,
17067
17541
  {
17068
17542
  variant: "label4",
@@ -17074,9 +17548,9 @@ var DataListItemLabel = (props) => {
17074
17548
  DataListItemLabel.displayName = "DataListItemLabel_UI";
17075
17549
 
17076
17550
  // src/components/DataList/DataListItemValue.tsx
17077
- var import_jsx_runtime319 = require("react/jsx-runtime");
17551
+ var import_jsx_runtime324 = require("react/jsx-runtime");
17078
17552
  var DataListItemValue = (props) => {
17079
- return /* @__PURE__ */ (0, import_jsx_runtime319.jsx)(
17553
+ return /* @__PURE__ */ (0, import_jsx_runtime324.jsx)(
17080
17554
  Text,
17081
17555
  {
17082
17556
  variant: "body3",
@@ -17131,6 +17605,15 @@ DataListItemValue.displayName = "DataListItemValue_UI";
17131
17605
  DataListItemValue,
17132
17606
  Divider,
17133
17607
  EditableHeading,
17608
+ EditableText,
17609
+ EditableTextCancelButton,
17610
+ EditableTextContext,
17611
+ EditableTextDisplay,
17612
+ EditableTextInput,
17613
+ EditableTextLabel,
17614
+ EditableTextRoot,
17615
+ EditableTextSubmitButton,
17616
+ EditableTextTrigger,
17134
17617
  Ellipsis,
17135
17618
  FileAmountLimitValidator,
17136
17619
  FileSizeValidator,