# ai-builder/2.7.10/assets/js/src/editor-blocks/table/index.js

AI Builder – Generate pages, blocks, images &amp; translate with AI, version 2.7.10. 335 lines.

- Page: https://pluginprobe.com/plugins/ai-builder/2.7.10/code/assets/js/src/editor-blocks/table/index.js
- Raw: https://pluginprobe.com/plugins/ai-builder/2.7.10/raw/assets/js/src/editor-blocks/table/index.js
- Modified: 2025-09-23T10:34:44+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/ai-builder/2.7.10/code/assets/js/src/editor-blocks/table/index.js#L10-L20`.

```javascript
const { registerBlockType } = wp.blocks;
const { __ } = wp.i18n;
const { PanelBody, ToggleControl, RangeControl, TextareaControl, Notice } =
  wp.components;

// Use HTML5 color input instead of WordPress ColorPicker to avoid compatibility issues
const SafeColorPicker = ({ color, onChange, disableAlpha }) => (
  <div style={{ position: "relative" }}>
    <input
      type="color"
      value={color || "#4f46e5"}
      onChange={(e) => onChange && onChange(e.target.value)}
      style={{
        width: "100%",
        height: "40px",
        border: "1px solid #ddd",
        borderRadius: "4px",
        cursor: "pointer",
      }}
    />
  </div>
);
const { InspectorControls, useBlockProps } = wp.blockEditor || wp.editor;

// CSS is enqueued via PHP

// Helper function to create a light version of a color
const lightenColor = (color, opacity = 0.03) => {
  if (!color) return "rgba(79, 70, 229, 0.03)";

  // Convert hex to RGB
  const hex = color.replace("#", "");
  const r = parseInt(hex.substr(0, 2), 16);
  const g = parseInt(hex.substr(2, 2), 16);
  const b = parseInt(hex.substr(4, 2), 16);

  const result = `rgba(${r}, ${g}, ${b}, ${opacity})`;
  console.log(`lightenColor(${color}, ${opacity}) = ${result}`);
  return result;
};

const SAMPLE = {
  columns: ["Name", "Email", "Role"],
  rows: [
    ["Jane Doe", "jane@example.com", "Editor"],
    ["John Smith", "john@example.com", "Author"],
    ["Alice", "alice@example.com", "Admin"],
  ],
};

registerBlockType("ai-builder/aibui-table", {
  title: __("Table (AI Builder)", "ai-builder"),
  icon: "table-col-after",
  category: "widgets",
  supports: { align: ["wide", "full"], html: false },
  attributes: {
    dataJson: { type: "string", default: JSON.stringify(SAMPLE, null, 2) },
    searchable: { type: "boolean", default: true },
    sortable: { type: "boolean", default: true },
    pageSize: { type: "number", default: 5 },
    primaryColor: { type: "string", default: "#4f46e5" },
  },
  edit: (props) => {
    const { attributes, setAttributes } = props;
    const { dataJson, searchable, sortable, pageSize, primaryColor } =
      attributes;
    const blockProps = useBlockProps({ className: "aibui-table" });

    let parsed = SAMPLE;
    let parseError = "";
    try {
      const obj = JSON.parse(dataJson || "{}");
      if (obj && Array.isArray(obj.columns) && Array.isArray(obj.rows)) {
        parsed = obj;
      }
    } catch (e) {
      parseError = e.message || "";
    }

    return (
      <div {...blockProps}>
        <InspectorControls>
          <PanelBody title={__("Settings", "ai-builder")} initialOpen>
            <ToggleControl
              label={__("Searchable", "ai-builder")}
              checked={searchable}
              onChange={(val) => setAttributes({ searchable: !!val })}
            />
            <ToggleControl
              label={__("Sortable", "ai-builder")}
              checked={sortable}
              onChange={(val) => setAttributes({ sortable: !!val })}
            />
            <RangeControl
              label={__("Page size", "ai-builder")}
              value={pageSize}
              onChange={(val) => setAttributes({ pageSize: Number(val) || 5 })}
              min={3}
              max={50}
            />
            <div style={{ marginTop: 12 }}>
              <p style={{ margin: "0 0 8px" }}>
                {__("Primary color", "ai-builder")}
              </p>
              <div
                style={{
                  display: "flex",
                  alignItems: "center",
                  gap: "8px",
                  marginBottom: "8px",
                  padding: "8px",
                  border: "1px solid #e5e7eb",
                  borderRadius: "6px",
                  backgroundColor: "#f9fafb",
                }}
              >
                <div
                  style={{
                    width: "24px",
                    height: "24px",
                    backgroundColor: primaryColor || "#4f46e5",
                    borderRadius: "4px",
                    border: "1px solid #e5e7eb",
                  }}
                />
                <span style={{ fontSize: "12px", color: "#6b7280" }}>
                  {primaryColor || "#4f46e5"}
                </span>
              </div>
              <SafeColorPicker
                color={primaryColor}
                onChange={(colorValue) => {
                  console.log("Setting primaryColor to:", colorValue);
                  setAttributes({ primaryColor: colorValue || "#4f46e5" });
                }}
                disableAlpha
              />
            </div>
            <TextareaControl
              label={__("Data (JSON)", "ai-builder")}
              help='{ "columns": ["Col1","Col2"], "rows": [["A","B"],["C","D"]] }'
              value={dataJson}
              onChange={(val) => setAttributes({ dataJson: val })}
              rows={10}
            />
            {parseError ? (
              <Notice status="warning" isDismissible={false}>
                {__("JSON parse error: ", "ai-builder") + parseError}
              </Notice>
            ) : null}
          </PanelBody>
        </InspectorControls>

        <TablePreview
          data={parsed}
          searchable={searchable}
          sortable={sortable}
          pageSize={pageSize}
          primaryColor={primaryColor}
        />
      </div>
    );
  },
  save: (props) => {
    const { attributes } = props;
    const { dataJson, searchable, sortable, pageSize, primaryColor } =
      attributes;
    let parsed = SAMPLE;
    try {
      const obj = JSON.parse(dataJson || "{}");
      if (obj && Array.isArray(obj.columns) && Array.isArray(obj.rows)) {
        parsed = obj;
      }
    } catch (e) {}
    const blockProps = wp.blockEditor
      ? wp.blockEditor.useBlockProps.save({ className: "aibui-table" })
      : {};
    return (
      <div {...blockProps}>
        <div
          className="aibui-table-container"
          data-searchable={searchable ? "1" : "0"}
          data-sortable={sortable ? "1" : "0"}
          data-page-size={Number(pageSize) || 5}
          style={{
            "--tb-primary": primaryColor || "#4f46e5",
            "--tb-primary-light": lightenColor(primaryColor, 0.08),
            "--tb-primary-lighter": lightenColor(primaryColor, 0.03),
          }}
        >
          <TableMarkup
            data={parsed}
            searchable={searchable}
            sortable={sortable}
            primaryColor={primaryColor}
            lightColor={lightenColor(primaryColor, 0.08)}
            lighterColor={lightenColor(primaryColor, 0.03)}
          />
          <div className="aibui-table-footer">
            <div className="aibui-table-pagination">
              <button className="aibui-btn">{"<"}</button>
              <span className="aibui-page-indicator">1 / …</span>
              <button className="aibui-btn">{">"}</button>
            </div>
          </div>
        </div>
      </div>
    );
  },
});

function TablePreview({ data, searchable, sortable, pageSize, primaryColor }) {
  return (
    <div
      className="aibui-table-container"
      data-searchable={searchable ? "1" : "0"}
      data-sortable={sortable ? "1" : "0"}
      data-page-size={Number(pageSize) || 5}
      style={{
        "--tb-primary": primaryColor || "#4f46e5",
        "--tb-primary-light": lightenColor(primaryColor, 0.08),
        "--tb-primary-lighter": lightenColor(primaryColor, 0.03),
      }}
    >
      <TableMarkup
        data={data}
        searchable={searchable}
        sortable={sortable}
        primaryColor={primaryColor}
        lightColor={lightenColor(primaryColor, 0.08)}
        lighterColor={lightenColor(primaryColor, 0.03)}
      />
      <div className="aibui-table-footer">
        <div className="aibui-table-pagination">
          <button className="aibui-btn">{"<"}</button>
          <span className="aibui-page-indicator">1 / …</span>
          <button className="aibui-btn">{">"}</button>
        </div>
      </div>
    </div>
  );
}

function TableMarkup({
  data,
  searchable,
  sortable,
  primaryColor,
  lightColor,
  lighterColor,
}) {
  const columns = Array.isArray(data.columns) ? data.columns : [];
  const rows = Array.isArray(data.rows) ? data.rows : [];
  return (
    <div
      className="aibui-table-wrap"
      style={{
        backgroundColor: lighterColor || "rgba(79, 70, 229, 0.03)",
        border: "1px solid rgba(0,0,0,0.08)",
      }}
    >
      {searchable ? (
        <div className="aibui-table-toolbar">
          <input
            className="aibui-input"
            type="search"
            placeholder={__("Search…", "ai-builder")}
          />
        </div>
      ) : null}
      <div className="aibui-table-scroll">
        <table className="aibui-table-el">
          <thead>
            <tr>
              {columns.map((c, i) => (
                <th
                  key={i}
                  style={{
                    backgroundColor: lightColor || "rgba(79, 70, 229, 0.08)",
                    borderBottom: "1px solid rgba(0,0,0,0.08)",
                  }}
                >
                  {sortable ? (
                    <button className="aibui-th-btn" type="button">
                      <span>{c}</span>
                      <span className="aibui-sort-icons" aria-hidden>
                        <svg
                          className="aibui-sort-icon aibui-sort-icon--up"
                          width="10"
                          height="10"
                          viewBox="0 0 10 10"
                        >
                          <path d="M5 2 L2 5 H8 Z" fill="#9ca3af" />
                        </svg>
                        <svg
                          className="aibui-sort-icon aibui-sort-icon--down"
                          width="10"
                          height="10"
                          viewBox="0 0 10 10"
                        >
                          <path d="M5 8 L2 5 H8 Z" fill="#9ca3af" />
                        </svg>
                      </span>
                    </button>
                  ) : (
                    <span>{c}</span>
                  )}
                </th>
              ))}
            </tr>
          </thead>
          <tbody>
            {rows.map((r, ri) => (
              <tr
                key={ri}
                style={{
                  backgroundColor:
                    ri % 2 === 0
                      ? "#ffffff"
                      : lighterColor || "rgba(79, 70, 229, 0.03)",
                  borderBottom: "1px solid rgba(0,0,0,0.06)",
                }}
              >
                {columns.map((_, ci) => (
                  <td key={ci}>{r && r[ci] != null ? String(r[ci]) : ""}</td>
                ))}
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

```
